Исследование объявлений о продаже квартир¶

Рынок недвижимости является основой рыночной экономики, поскольку представляет собой сферу вложений капитала в объекты недвижимости и систему экономических отношений, возникающих при операциях с недвижимостью. Одним из основных сегментов рынка недвижимости является рынок жилья, к объектам которого относят жилые дома и квартиры, их части, а также комнаты.

С появлением интернета процесс поиска недвижимости стал проще. Создание специальных сайтов позволяет ускорить процесс привлечения покупателей и снизить затраты продавцов на рекламу объекта недвижимости. Способом информирования покупателей о продаваемом объекте недвижимости является размещение объявлений на таких интернет-площадках.

В России насчитывается более 2,5 тысяч сайтов с объявлениями о продаже и аренде квартир. Яндекс.Недвижимость — крупнейший сервис поиска и подбора недвижимости в России с ежемесячной аудиторией более 4 миллионов человек. На сервисе собрана информация о продаже и сдаче в аренду комнат, квартир и домов на вторичном рынке, а также объявления о продаже недвижимости в новостройках, расположенных во всех регионах страны.

Приложение Яндекс.Недвижимость разработано с учётом поведенческих алгоритмов. Если человек замечен в подозрительной активности, его предложения будут проверены более тщательно. Автоматизированная система отследит аномалии и мошеннические действия. За счёт такой системы риски столкнуться с мошенником минимизируются.

В нашем распоряжении находятся данные сервиса Яндекс.Недвижимость: архив объявлений о продаже квартир в Санкт-Петербурге и других населённых пунктах Ленинградской области за несколько лет.

По каждой квартире на продажу доступны два вида данных. Первые внесены пользователем, вторые — получены автоматически на основе картографических данных. Например, расстояние до центра, аэропорта, ближайшего парка и водоёма.

Ключевой вопрос при купле-продажи квартиры — как определить её рыночную стоимость в конкретный момент времени. Рыночная стоимость — это цена, за которую объект может быть продан в условиях свободного рынка и с учётом конкуренции за период, соответствующий среднему сроку экспозиции. Рыночную цену жилья продавцу надо знать, чтобы не продешевить, а покупателю — чтобы не переплатить.

Цель исследования: выявить признаки, влияющие на конечную рыночную стоимость квартиры.

Задачи исследования:

  • выполнить предобработку данных;
  • изучить обработанные данные;
  • найти особенности и выявить зависимости между признаками.

Содержание

  • 1  Обзор данных
    • 1.1  Импорт библиотек и предварительные настройки
    • 1.2  Чтение файла и загрузка данных
    • 1.3  Общая характеристика набора данных
    • 1.4  Преобразование наименований признаков
  • 2  Понимание данных
  • 3  Описание данных
    • 3.1  Признаки, измеряемые в шкале отношений и шкале разностей
    • 3.2  Признаки, измеряемые в порядковой шкале
    • 3.3  Признаки, измеряемые в интервальной шкале, в номинальной шкале, в дихотомической шкале
  • 4  Предобработка данных
    • 4.1  Обработка текстовых значений и извлечение вложенных сведений
    • 4.2  Обработка аномальных и несогласованных значений
      • 4.2.1  Жилая площадь
      • 4.2.2  Общая площадь меньше или равна сумме площадей: жилой и кухни
      • 4.2.3  Маленькая площадь вспомогательных помещений
      • 4.2.4  Этажность здания
      • 4.2.5  Расстояние до аэропорта
      • 4.2.6  Расстояние до ближайшего парка
      • 4.2.7  Высота потолков
      • 4.2.8  Количество комнат
    • 4.3  Обработка пропусков
      • 4.3.1  Сведения об апартаментах
      • 4.3.2  Количество балконов
      • 4.3.3  Название и тип населённого пункта
      • 4.3.4  Расстояние до ближайшего парка
      • 4.3.5  Расстояние до ближайшего водоёма
      • 4.3.6  Расстояние до центра Санкт-Петербурга
      • 4.3.7  Расстояние до аэропорта
      • 4.3.8  Этажность здания
      • 4.3.9  Высота потолков
      • 4.3.10  Жилая площадь и площадь кухни в квартирах-студиях
      • 4.3.11  Жилая площадь и площадь кухни
      • 4.3.12  Картографические данные
    • 4.4  Обработка хронометрических данных
    • 4.5  Изменение типов данных
    • 4.6  Обработка дубликатов
    • 4.7  Обогащение данных
      • 4.7.1  Создание производных признаков
      • 4.7.2  Категоризация данных
  • 5  Исследовательский анализ данных
    • 5.1  Описательный анализ данных
      • 5.1.1  Хронометрические данные
        • 5.1.1.1  Дата публикации объявления
        • 5.1.1.2  Год публикации объвления
        • 5.1.1.3  Месяц публикации объявления
        • 5.1.1.4  Дни недели
        • 5.1.1.5  Количество дней публикации
        • 5.1.1.6  Дата снятия с публикации
      • 5.1.2  Характеристики здания и его местоположения
        • 5.1.2.1  Распределение квартир между городом и областью
        • 5.1.2.2  Тип населённого пункта
        • 5.1.2.3  Наименование населённых пунктов
        • 5.1.2.4  Расстояние до центра Санкт-Петербурга
        • 5.1.2.5  Расстояние до аэропорта
        • 5.1.2.6  Количество парков
        • 5.1.2.7  Расстояние до ближайшего парка
        • 5.1.2.8  Количество водоёмов
        • 5.1.2.9  Расстояние до ближайшего водоёма
        • 5.1.2.10  Этажность зданий
      • 5.1.3  Характеристики объектов недвижимости
        • 5.1.3.1  Тип этажа
        • 5.1.3.2  Номер этажа
        • 5.1.3.3  Количество комнат
        • 5.1.3.4  Общая площадь
        • 5.1.3.5  Жилая площадь
        • 5.1.3.6  Площадь кухни
        • 5.1.3.7  Количество балконов
        • 5.1.3.8  Высота потолков
        • 5.1.3.9  Студия
        • 5.1.3.10  Апартаменты
      • 5.1.4  Финансовые характеристики
        • 5.1.4.1  Цена на момент снятия с публикации
        • 5.1.4.2  Цена за квадратный метр
      • 5.1.5  Дополнительные данные
        • 5.1.5.1  Количество фотографий
    • 5.2  Корреляционный анализ данных
      • 5.2.1  Средняя цена квадратного метра
      • 5.2.2  Средняя стоимость квартир в Санкт-Петербурге
      • 5.2.3  Стоимость объекта — общая площадь
      • 5.2.4  Стоимость объекта — жилая площадь
      • 5.2.5  Стоимость объекта — площадь кухни
      • 5.2.6  Стоимость объекта — количество комнат
      • 5.2.7  Стоимость объекта — тип этажа
      • 5.2.8  Стоимость объекта — день недели публикации
      • 5.2.9  Стоимость объекта — месяц публикации
      • 5.2.10  Стоимость объекта — год публикации
  • 6  Общий вывод

Обзор данных¶

Импорт библиотек и предварительные настройки¶

In [1]:
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
import seaborn as sns
import sys
import os
import warnings

pd.set_option('display.max_columns', None)
np.set_printoptions(threshold=sys.maxsize)
warnings.filterwarnings('ignore')

Чтение файла и загрузка данных¶

Все данные хранятся в одном файле.
Файл данных real_estate_data.csv имеет формат CSV, в котором в качестве разделителя испольуется \t.

In [2]:
pth1 = r'C:\Users\Георгий\Documents\DS_projects\real_estate_data.csv'
pth2 = '/datasets/real_estate_data.csv'
pth3 = '/content/real_estate_data.csv'

if os.path.exists(pth1):
    data = pd.read_csv(pth1, sep='\t')
elif os.path.exists(pth2):
    data = pd.read_csv(pth2, sep='\t')
elif os.path.exists(pth3):
    data = pd.read_csv(pth3, sep='\t')
else:
    print('Something is wrong')

Убедимся, что данные подгрузились верно, без ошибок.

Для этого выведем первые 10 строк и последние 10 строк набора данных.

In [3]:
data.head(10)
Out[3]:
total_images last_price total_area first_day_exposition rooms ceiling_height floors_total living_area floor is_apartment studio open_plan kitchen_area balcony locality_name airports_nearest cityCenters_nearest parks_around3000 parks_nearest ponds_around3000 ponds_nearest days_exposition
0 20 13000000.0 108.00 2019-03-07T00:00:00 3 2.70 16.0 51.00 8 NaN False False 25.00 NaN Санкт-Петербург 18863.0 16028.0 1.0 482.0 2.0 755.0 NaN
1 7 3350000.0 40.40 2018-12-04T00:00:00 1 NaN 11.0 18.60 1 NaN False False 11.00 2.0 посёлок Шушары 12817.0 18603.0 0.0 NaN 0.0 NaN 81.0
2 10 5196000.0 56.00 2015-08-20T00:00:00 2 NaN 5.0 34.30 4 NaN False False 8.30 0.0 Санкт-Петербург 21741.0 13933.0 1.0 90.0 2.0 574.0 558.0
3 0 64900000.0 159.00 2015-07-24T00:00:00 3 NaN 14.0 NaN 9 NaN False False NaN 0.0 Санкт-Петербург 28098.0 6800.0 2.0 84.0 3.0 234.0 424.0
4 2 10000000.0 100.00 2018-06-19T00:00:00 2 3.03 14.0 32.00 13 NaN False False 41.00 NaN Санкт-Петербург 31856.0 8098.0 2.0 112.0 1.0 48.0 121.0
5 10 2890000.0 30.40 2018-09-10T00:00:00 1 NaN 12.0 14.40 5 NaN False False 9.10 NaN городской посёлок Янино-1 NaN NaN NaN NaN NaN NaN 55.0
6 6 3700000.0 37.30 2017-11-02T00:00:00 1 NaN 26.0 10.60 6 NaN False False 14.40 1.0 посёлок Парголово 52996.0 19143.0 0.0 NaN 0.0 NaN 155.0
7 5 7915000.0 71.60 2019-04-18T00:00:00 2 NaN 24.0 NaN 22 NaN False False 18.90 2.0 Санкт-Петербург 23982.0 11634.0 0.0 NaN 0.0 NaN NaN
8 20 2900000.0 33.16 2018-05-23T00:00:00 1 NaN 27.0 15.43 26 NaN False False 8.81 NaN посёлок Мурино NaN NaN NaN NaN NaN NaN 189.0
9 18 5400000.0 61.00 2017-02-26T00:00:00 3 2.50 9.0 43.60 7 NaN False False 6.50 2.0 Санкт-Петербург 50898.0 15008.0 0.0 NaN 0.0 NaN 289.0
In [4]:
data.tail(10)
Out[4]:
total_images last_price total_area first_day_exposition rooms ceiling_height floors_total living_area floor is_apartment studio open_plan kitchen_area balcony locality_name airports_nearest cityCenters_nearest parks_around3000 parks_nearest ponds_around3000 ponds_nearest days_exposition
23689 13 3550000.0 35.30 2018-02-28T00:00:00 1 2.86 15.0 16.3 4 NaN False False 9.10 2.0 Санкт-Петербург 17284.0 16081.0 1.0 353.0 2.0 652.0 29.0
23690 3 5500000.0 52.00 2018-07-19T00:00:00 2 NaN 5.0 31.0 2 NaN False False 6.00 NaN Санкт-Петербург 20151.0 6263.0 1.0 300.0 0.0 NaN 15.0
23691 11 9470000.0 72.90 2016-10-13T00:00:00 2 2.75 25.0 40.3 7 NaN False False 10.60 1.0 Санкт-Петербург 19424.0 4489.0 0.0 NaN 1.0 806.0 519.0
23692 2 1350000.0 30.00 2017-07-07T00:00:00 1 NaN 5.0 17.5 4 NaN False False 6.00 NaN Тихвин NaN NaN NaN NaN NaN NaN 413.0
23693 9 4600000.0 62.40 2016-08-05T00:00:00 3 2.60 9.0 40.0 8 NaN False False 8.00 0.0 Петергоф 45602.0 34104.0 1.0 352.0 1.0 675.0 239.0
23694 9 9700000.0 133.81 2017-03-21T00:00:00 3 3.70 5.0 73.3 3 NaN False False 13.83 NaN Санкт-Петербург 24665.0 4232.0 1.0 796.0 3.0 381.0 NaN
23695 14 3100000.0 59.00 2018-01-15T00:00:00 3 NaN 5.0 38.0 4 NaN False False 8.50 NaN Тосно NaN NaN NaN NaN NaN NaN 45.0
23696 18 2500000.0 56.70 2018-02-11T00:00:00 2 NaN 3.0 29.7 1 NaN False False NaN NaN село Рождествено NaN NaN NaN NaN NaN NaN NaN
23697 13 11475000.0 76.75 2017-03-28T00:00:00 2 3.00 17.0 NaN 12 NaN False False 23.30 2.0 Санкт-Петербург 39140.0 10364.0 2.0 173.0 3.0 196.0 602.0
23698 4 1350000.0 32.30 2017-07-21T00:00:00 1 2.50 5.0 12.3 1 NaN False False 9.00 NaN поселок Новый Учхоз NaN NaN NaN NaN NaN NaN NaN

Общая характеристика набора данных¶

Размер набора данных:

In [5]:
data.shape
Out[5]:
(23699, 22)

Количество дубликатов в наименованиях признаков:

In [6]:
data.columns.duplicated().sum()
Out[6]:
0

Уникальные наименования признаков:

In [7]:
data.columns.sort_values().tolist()
Out[7]:
['airports_nearest',
 'balcony',
 'ceiling_height',
 'cityCenters_nearest',
 'days_exposition',
 'first_day_exposition',
 'floor',
 'floors_total',
 'is_apartment',
 'kitchen_area',
 'last_price',
 'living_area',
 'locality_name',
 'open_plan',
 'parks_around3000',
 'parks_nearest',
 'ponds_around3000',
 'ponds_nearest',
 'rooms',
 'studio',
 'total_area',
 'total_images']

Количество элементов данных:

In [8]:
data.size
Out[8]:
521378

Типы данных набора данных:

In [9]:
data.dtypes.value_counts()
Out[9]:
float64    14
int64       3
object      3
bool        2
Name: count, dtype: int64

Пропущенные значения в данных:

In [10]:
data.isna().sum().sort_values()
Out[10]:
total_images                0
open_plan                   0
floor                       0
rooms                       0
studio                      0
total_area                  0
last_price                  0
first_day_exposition        0
locality_name              49
floors_total               86
living_area              1903
kitchen_area             2278
days_exposition          3181
ponds_around3000         5518
parks_around3000         5518
cityCenters_nearest      5519
airports_nearest         5542
ceiling_height           9195
balcony                 11519
ponds_nearest           14589
parks_nearest           15620
is_apartment            20924
dtype: int64

Распределение пропущенных значений в наборе данных:

In [11]:
sns.heatmap(data.isna(), cmap=sns.color_palette(['#000000', '#ffffff']))
plt.title('Тепловая карта\nраспределения пропущенных значений')
plt.xlabel('Название признака')
plt.ylabel('Номер записи')
plt.show()

Количество признаков без пропущенных значений:

In [12]:
(data.isna().sum() == 0).sum()
Out[12]:
8

Общее количество пропущенных значений:

In [13]:
data.isna().sum().sum()
Out[13]:
101441

Промежуточный вывод

  • Набор данных содержит 22 уникальных признака и 23 699 записей.
  • Всего: 521 378 элементов данных.
  • Набор данных содержит данные следующего типа:
    • целочисленный — 3 признака,
    • вещественный — 14 признаков,
    • логический — 2 признака,
    • смешанного типа — 3 признака.
  • Все признаки содержат значения (не являются пустыми).
  • 8 признаков не содержат пропущенные значения.
  • 14 признаков содержат пропущенные значения:
    • распределение пропусков в данных не носит регулярный характер,
    • всего в данных 101 441 пропущенное значение — около 20 % от всех элементов данных.
  • Необходимо привести названия признаков к "змеиному_регистру".

Преобразование наименований признаков¶

Приведение названий столбцов к "змеиному_регистру":

In [14]:
data = data.rename(columns = {
        'cityCenters_nearest': 'city_centers_nearest',
        'parks_around3000': 'parks_around_3000',
        'ponds_around3000': 'ponds_around_3000'
    }
)
data.columns.unique().sort_values().to_list()
Out[14]:
['airports_nearest',
 'balcony',
 'ceiling_height',
 'city_centers_nearest',
 'days_exposition',
 'first_day_exposition',
 'floor',
 'floors_total',
 'is_apartment',
 'kitchen_area',
 'last_price',
 'living_area',
 'locality_name',
 'open_plan',
 'parks_around_3000',
 'parks_nearest',
 'ponds_around_3000',
 'ponds_nearest',
 'rooms',
 'studio',
 'total_area',
 'total_images']

Понимание данных¶

Несмотря на то, что все данные были получены из двух источников: картографические данные собраны системой автоматически, а остальные данные введены пользователем вручную — по своему содержанию их можно разделить на несколько категорий.

  • Признаки, характеризующие объект недвижимости.
  • Признаки, характеризующие место расположения объекта недвижимости.
  • Признаки, относящиеся к жизненному циклу объявления и содержащие финансовую информацию.
  • Дополнительные признаки, носящие вспомогательный характер.

Согласно Гражданскому кодексу РФ:

К недвижимым вещам (недвижимое имущество, недвижимость) относятся <...> здания...

Согласно Федеральному закону от 30.12.2009 г. № 384-ФЗ «Технический регламент о безопасности зданий и сооружений»:

Здание — результат строительства, представляющий собой объёмную строительную систему, имеющую надземную и (или) подземную части, включающую в себя помещения, сети инженерно-технического обеспечения и системы инженерно-технического обеспечения и предназначенную для проживания и (или) деятельности людей, размещения производства, хранения продукции или содержания животных.

Помещение — часть объёма здания или сооружения, имеющая определённое назначение и ограниченная строительными конструкциями.

Среди всех помещений Жилищный кодекс РФ выделяет жилые помещения:

Жилым помещением признается изолированное помещение, которое является недвижимым имуществом и пригодно для постоянного проживания граждан (отвечает установленным санитарным и техническим правилам и нормам, иным требованиям законодательства).

Причём все жилые помещения делятся на виды (ЖК РФ):

  1. Жилой дом, часть жилого дома.

Жилым домом признается индивидуально-определённое здание, которое состоит из комнат, а также помещений вспомогательного использования, предназначенных для удовлетворения гражданами бытовых и иных нужд, связанных с их проживанием в таком здании.

  1. Квартира, часть квартиры.

Квартирой признается структурно обособленное помещение в многоквартирном доме, обеспечивающее возможность прямого доступа к помещениям общего пользования в таком доме и состоящее из одной или нескольких комнат, а также помещений вспомогательного использования, предназначенных для удовлетворения гражданами бытовых и иных нужд, связанных с их проживанием в таком обособленном помещении.

  1. Комната.

Комнатой признается часть жилого дома или квартиры, предназначенная для использования в качестве места непосредственного проживания граждан в жилом доме или квартире.

Кроме того, многоквартирное жилое здание (многоквартирный дом) определяется сводом правил
СП 54.13330.2022 "СНиП 31-01-2003 Здания жилые многоквартирные":

Здание жилое многоквартирное — жилое здание, включающее две и более квартиры, помещения общего пользования и общие инженерные системы.

*Характеристики объекта недвижимости*

Основными геометрическими параметрами являются площадь и высота помещения.

Площадь

total_area — общая площадь (м²)
Признак является количественным, непрерывным.
Шкала измерения признака: шкала отношений.

Согласно ЖК РФ:

Общая площадь жилого помещения состоит из суммы площади всех частей такого помещения, включая площадь помещений вспомогательного использования, предназначенных для удовлетворения гражданами бытовых и иных нужд, связанных с их проживанием в жилом помещении, за исключением балконов, лоджий, веранд и террас.

Таким образом, жилая площадь — это сумма площадей всех частей жилого помещения: в случае квартиры — сумма площадей всех комнат.

living_area — жилая площадь (м²)
Признак является количественным, непрерывным.
Шкала измерения признака: шкала отношений.

СП 54.13330.2022 "СНиП 31-01-2003 Здания жилые многоквартирные" даёт определение вспомогательного помещения:

Помещение вспомогательное — помещение квартиры для обеспечения коммуникационных, санитарных, технических и хозяйственно-бытовых нужд, в том числе: кухня (или кухня-столовая), передняя, внутриквартирные холл и коридор, ванная комната или душевая, уборная, туалет или совмещённый санузел, кладовая, постирочная, помещение теплогенераторной и т. п.

Кухня может быть реализована в виде отдельного помещения, либо отделена зона под неё.
Согласно СП 54.13330.2022 "СНиП 31-01-2003 Здания жилые многоквартирные":

Кухня — вспомогательное помещение с обеденной зоной, а также местом для размещения кухонного оборудования для приготовления пищи, мойки, хранения посуды и инвентаря.

Кухня-ниша — зона, предназначенная для приготовления пищи, расположенная смежно с жилым или вспомогательным помещением квартиры и оборудованная электрической плитой (электрическими варочной панелью и жарочным шкафом), мойкой и приточно-вытяжной вентиляцией с механическим или естественным побуждением.

kitchen_area — площадь кухни (м²)
Признак является количественным, непрерывным.
Шкала измерения признака: шкала отношений.

Таким образом, имеет место следующее соотношение:

$Общая\ площадь = Жилая\ площадь + Площадь\ вспомогательных\ помещений$

Получается, что

$Площадь\ кухни < Площадь\ помещений\ вспомогательного\ использования$.

Исключение могут составлять объявления о продажи изолированной комнаты или доли в квартире: в них может быть указано, что

$Жилая\ площадь = Общая\ площадь$.

И даже может случиться так, что

$Площадь\ кухни > Площадь\ остальных\ помещений\ вспомогательного\ использования$.

Высота

Высота помещения — это расстояние между полом и потолком. Однако на эту величину могут влиять напольное и потолочное покрытия, тем самым уменьшая её значение.

ceiling_height — высота потолков (м)
Признак является количественным, непрерывным.
Шкала измерения признака: шкала отношений.

Планировка

В каждом объекте недвижимости выделяют жилые комнаты или их не выделяют, а превращают все комнаты в одну большую квартиру-студию.

rooms — общее количество комнат в квартире
Признак является качественным, порядковым.
Шкала измерения признака: порядковая шкала.

По данным сервиса Яндекс.Недвижимость количество комнат:
при свободной планировке указывается по паспорту объекта;
не указывается для студий.

В нормативно-правовых актах РФ понятие "квартира-студия" не определено. Дом.рф даёт такое определение:

Квартира-студия представляет собой одно большое помещение, которое включает в себя комнату, кухню, прихожую. Отдельным помещением остаётся только санузел.

Квартира-студия может быть сформирована в результате перепланировки квартиры, либо изначально строится по проекту застройщика.
Юридически квартира-студия ничем не отличается от обычной квартиры.

studio — квартира-студия
Признак является категориальным, бинарным.
Шкала измерения признака: дихотомическая шкала.

По данным сервиса Яндекс.Недвижимость:
элемент не используется для объектов со свободной планировкой.

Если в квартире отсутствуют межкомнатные перекрытия, а пространство квартиры ограничено только внешними и межквартирными стенами, то говорят о свободной планировке квартиры.
Фактически, такие квартиры являются квартирами-студиями.
Юридически понятия "свободная планировка" не существует.
Основное достоинство квартир со свободной планировкой — открытое пространство. Свободная планировка предполагает возможности по изменению размеров комнат и их расположения.

open_plan — свободная планировка
Признак является категориальным, бинарным.
Шкала измерения признака: дихотомическая шкала.

По данным сервиса Яндекс.Недвижимость:
элемент не используется для студий.

Понятие балкона определяется в СП 54.13330.2022 "СНиП 31-01-2003 Здания жилые многоквартирные":

Балкон в жилом многоквартирном здании — выступающая из плоскости наружной стены ограждённая площадка, имеющая ограниченную глубину, взаимоувязанную с освещением примыкающего помещения; может выполняться с покрытием и остеклением.

Кроте того, существует ещё и французский балкон:

Балкон французский — световой проем, в который установлен балконный блок с внешним визуально проницаемым защитным ограждением.

balcony — количество балконов
Признак является качественным, порядковым.
Шкала измерения признака: порядковая шкала.

Балкон необходимо отличать от лоджии:

Лоджия — вспомогательное неотапливаемое помещение, встроенное в здание или пристроенное к нему, имеющее стены с трёх сторон (или с двух сторон при угловом расположении) на всю высоту этажа, ограждение с открытой стороны (сторон) и ограниченную глубину, взаимоувязанную с освещением помещения, к которому примыкает; может выполняться с покрытием и остеклением.

Расположение в здании

Согласно СП 54.13330.2022 "СНиП 31-01-2003 Здания жилые многоквартирные":

Этаж жилого многоквартирного здания — часть здания между высотными отметками верха перекрытия или пола по грунту и верха вышерасположенного перекрытия (покрытия), включающая пространство высотой в чистоте (от пола до потолка) 1,8 м и более, предназначенная для размещения помещений жилых, вспомогательных, общего пользования, общественного назначения, технических.

Этаж надземный в жилом многоквартирном здании — этаж с отметкой пола не ниже наиболее низкой планировочной отметки земли.

Этаж первый в жилом многоквартирном здании — этаж нижний надземный, доступный для входа с прилегающей территории.

Этаж подземный — этаж с отметкой пола ниже наиболее низкой планировочной отметки уровня земли на всю высоту помещений.

Этаж мансардный (мансарда) в жилом многоквартирном здании — этаж, фасад которого полностью или частично образован поверхностью (поверхностями) наклонной, ломаной или криволинейной крыши, при этом линия пересечения плоскости крыши и фасада должна быть на высоте не более 1,5 м от уровня пола мансардного этажа, в котором размещены жилые помещения, вспомогательные или помещения общественного назначения.

floor — этаж, на котором находится объект
Признак является качественным, порядковым.
Шкала измерения признака: порядковая шкала.

Особенности юридического статуса

Согласно СП 160.1325800.2014 "Здания и комплексы многофункциональные. Правила проектирования":

Апартаменты — жилые помещения, предназначенные для временного проживания, могут проектироваться в виде гостиничных номеров или квартирного типа для временного проживания (например, при сдаче внаём).

В настоящий момент правовой статус апартаментов не урегулирован. Поскольку Жилищный кодекс РФ не относит апартаменты к жилым помещениям, их относят к нежилым помещениям. Например, налогообложение апартаментов осуществляется в порядке, предусмотренном для нежилых помещений (Письмо Минфина РФ от 7.12.2020 г. N 03-05-04-01/106713). Кроме того, в апартаментах нельзя оформить постоянную регистрацию по месту жительства и пребывания.

is_apartment — апартаменты
Признак является категориальным, бинарным.
Шкала измерения признака: дихотомическая шкала.

*Характеристики здания*

Этажность здания

В соответствии с Инструкцией о проведении учёта жилищного фонда в Российской Федерации, утверждённой приказом Минземстроя от 04.08.98 N 37:

Этажность жилого дома должна определяться по числу надземных этажей.
При определении этажности в число надземных этажей включаются цокольные этажи, если верх перекрытия цокольного этажа возвышается над уровнем планировочной отметки земли не менее чем на 2 м.
Первым надземным считается этаж, пол которого находится не ниже уровня планировочной земли. Если отдельные части жилого дома имеют разное количество надземных этажей, его этажность определяется по наибольшему количеству этажей в здании.

В Письме Федерального агентства кадастра объектов недвижимости от 27 августа 2008 года N АМ/1567 "Об этажности жилого дома" отмечено, что под количеством этажей подразумевается "общее число этажей здания". Таким образом, этажность здания будет определяться как разность показателя "количество этажей" и показателя "количество подземных этажей".

floors_total — общее количество этажей в здании
Признак является качественным, порядковым.
Шкала измерения признака: порядковая шкала.

В сервисе Яндекс.Недвижимость под этим показателем подразумевается этажность здания.

Положение здания на местности

Населенный пункт — компактная территория совместного и постоянного или преимущественного проживания населения, имеющая сосредоточенную застройку в пределах установленной границы, официально получившая такой статус.

locality_name — название населённого пункта
Признак является категориальным, номинальным.
Шкала измерения признака: номинальная шкала.

Картографические данные взяты с сервиса Яндекс.Карты.

Сами дома на картах, их адреса, названия ЖК — указывают Яндекс Карты. Внести изменения в карты сервис Недвижимости не может.

Для измерения расстояний используется Линейка.

В Яндекс.Картах центр города Санкт-Петербурга расположен на Дворцовой площади возле Александровской колонны.

Расстояние между двумя точками — это длина отрезка, соединяющая эти точки. Однако сервис Яндекс.Карты позволяет также измерять расстояние по ломанной линии.

Измерить расстояние на карте можно по прямой или по ломаной линии, повторяя линии улиц.

Для понимания того, что из себя представляют расстояния в данных, можно провести эксперимент. Для этого необходимо измерить расстояние между центром Кронштадта и центром Санкт-Петербурга. Кронштадт — идеальный вариант для эксперимента: город расположен на острове в Финском заливе. Расстояние по прямой значительно отличается от расстояния, преодолеваемого по автомобильным дорогам. Если расстояние по прямо порядка 30 км, то расстояние по дороге порядка 50 км. Таким образом, все приведённые в наборе данные о расстоянии являются расстояниями, преодолеваемыми по автомобильным дорогам.

city_centers_nearest — расстояние до центра города Санкт-Петербурга (м)
Признак является количественным, непрерывным.
Шкала измерения признака: шкала отношений.

В Санкт-Петербурге три аэропорта:

  • Международный аэропорт Пулково (с терминалами Пулково 1 и Пулково 2).
  • Военная база в Левашево.
  • Аэродром Ржевка.

Пассажирские рейсы по внутренним и международным направлениям обслуживает только аэропорт Пулково.

airports_nearest — расстояние до аэропорта Пулково (м)
Признак является количественным, непрерывным.
Шкала измерения признака: шкала отношений.

Парк — большой сад, роща с аллеями, цветниками, прудами и т. п.
В сервисе Яндекс.Карты контур парка либо совпадает с его административной границей, либо проводится в соответствии с ситуацией на местности (например, по забору).

parks_nearest — расстояние до ближайшего парка (м)
Признак является количественным, непрерывным.
Шкала измерения признака: шкала отношений.

parks_around_3000 — число парков в радиусе 3 км
Признак является качественным, порядковым.
Шкала измерения признака: порядковая шкала.

Водоём — место скопления воды.
В сервисе Яндекс.Карты это контурный гидрографический объект.

Контурные объекты — водоёмы (участки открытой водной поверхности: моря, заливы, гавани, проливы, озёра, водохранилища, пруды, акватории рек), ледники, болота, открытые бассейны.

ponds_nearest — расстояние до ближайшего водоёма (м)
Признак является количественным, непрерывным.
Шкала измерения признака: шкала отношений.

ponds_around_3000 — число водоёмов в радиусе 3 км
Признак является качественным, порядковым.
Шкала измерения признака: порядковая шкала.

Расстояния до парков и водоёмов — это расстояния, преодолеваемые пешком по пересечённой местности.
Экспериментально это можно установить, измерив расстояние от ЖК "Князь Александр Невский" до ближайшего водоёма — реки Невы.

*Характеристики объявления*

Хронометричекие данные

Дата публикации — дата подачи (создания) объявления.

К формату даты сервис Яндекс.Недвижимость предъявляет требование:

Все даты и время следует указывать согласно стандарту ISO 8601.

first_day_exposition — дата публикации
Признак является количественным, дискретным.
Шкала измерения признака: интервальная шкала.

Период (срок) размещения объявления — количество дней размещения объявления на сервисе от момента публикации до момента снятия с публикации.

days_exposition — период размещения объявления
Признак является количественным, дискретным.
Шкала измерения признака: шкала разностей.

Финансовые данные

Цена — стоимость объекта недвижимости, выраженная в рублях. Оплата стоимости объекта является условием сделки.
Цена за объект недвижимости является актуальной во время всего срока размещения объявления.

last_price — цена на момент снятия с публикации (руб.)
Признак является количественным, непрерывным.
Шкала измерения признака: шкала отношений.

Цена на момент снятия с публикации — целевой признак.

*Дополнительные данные*

Согласно требованиям сервиса Яндекс.Недвижимость фотографии объекта (в том числе планировок) являются обязательным элементом объявления.

total_images — количество фотографий квартиры в объявлении
Признак является качественным, порядковым.
Шкала измерения признака: порядковая шкала.

Описание данных¶

In [15]:
def graph(value):
    '''
    Функция строит диаграмму распределения значений и диаграмму размаха
    исследуемых данных.

    Принимает название признака исследуемого набора данных.

    '''

    fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(15, 6))
    ax1.set_title('Диаграмма распределения и диаграмма размаха' +
                  f'\nзначений признака {value}')
    ax1.hist(data.loc[data[value].notna(), value], bins=100)
    ax1.tick_params(labelbottom=False)
    ax1.set_ylabel('Частота')
    ax2.boxplot(data.loc[data[value].notna(), value], vert=False)
    ax2.tick_params(left=False, labelleft=False)
    ax2.set_xlabel(f'Значения признака {value}')
    plt.show()

Признаки, измеряемые в шкале отношений и шкале разностей¶

In [16]:
columns = ['last_price', 'total_area', 'living_area', 'kitchen_area',
           'ceiling_height', 'city_centers_nearest', 'airports_nearest',
           'parks_nearest', 'ponds_nearest', 'days_exposition']
In [17]:
data[columns].describe().round(2)
Out[17]:
last_price total_area living_area kitchen_area ceiling_height city_centers_nearest airports_nearest parks_nearest ponds_nearest days_exposition
count 2.369900e+04 23699.00 21796.00 21421.00 14504.00 18180.00 18157.00 8079.00 9110.00 20518.00
mean 6.541549e+06 60.35 34.46 10.57 2.77 14191.28 28793.67 490.80 517.98 180.89
std 1.088701e+07 35.65 22.03 5.91 1.26 8608.39 12630.88 342.32 277.72 219.73
min 1.219000e+04 12.00 2.00 1.30 1.00 181.00 0.00 1.00 13.00 1.00
25% 3.400000e+06 40.00 18.60 7.00 2.52 9238.00 18585.00 288.00 294.00 45.00
50% 4.650000e+06 52.00 30.00 9.10 2.65 13098.50 26726.00 455.00 502.00 95.00
75% 6.800000e+06 69.90 42.30 12.00 2.80 16293.00 37273.00 612.00 729.00 232.00
max 7.630000e+08 900.00 409.70 112.00 100.00 65968.00 84869.00 3190.00 1344.00 1580.00
In [18]:
for column in columns:
    graph(column)

last_price — цена на момент снятия с публикации (руб.)
Значения определены для всех записей.
Значения определены с точностью до 1 руб.
Минимальное значение составляет 12 190 руб., максимальное — 763 млн руб.
Среднее арифметическое значение равно 6,54 млн руб., медиана — 4,65 млн руб.
Первый, второй и третий квартили — величины одного порядка (10$^6$ руб.). Не менее чем у половины объектов недвижимости значение стоимости попадает в диапазон 3—7 млн руб. Большое отличие среднего арифметического от медианы следует из того, что в выборке присутствуют объекты недвижимости, стоимость которых на 1—2 порядка выше (10$^7$—10$^8$ руб.). На диаграмме размаха эти значения не накрываются "ящиком с усами". Минимальное значение стоимости представляется сомнительным, поскольку оно меньше медианного значения на два порядка (10$^4$ руб.). Скорее всего, это свидетельствует о наличии ошибки в данных. Оценка распределения значений по гистограмме не представляется возможной из-за значительного размаха — в 4 порядка.

total_area — общая площадь (м²)
Значения определены для всех записей.
Значения определены с точностью до 0,01 м².
Минимальное значение составляет 12 м², максимальное — 900 м².
Среднее арифметическое значение равно 60,35 м², медиана — 52 м².
Первый, второй и третий квартили — близкие по значению величины. Не менее чем у половины объектов недвижимости значение общей площади попадает в диапазон 40—70 м². Наличие в выборке объектов недвижимости с большой общей площадью (более 200 м²) приводит к значительному отличию среднего арифметического от медианы. На диаграмме размаха эти значения не накрываются "ящиком с усами". По гистограмме можно охарактеризовать распределение значений как унимодальное с положительной ассиметрией пика.

living_area — жилая площадь (м²)
Значения определены для 21 796 записей — это 92 % всех записей.
Значения определены с точностью до 0,01 м².
Минимальное значение составляет 2 м², максимальное — 409,70 м².
Среднее арифметическое значение равно 34,46 м², медиана — 30 м².
Первый, второй и третий квартили — близкие по значению величины. Почти у половины объектов недвижимости значение жилой площади попадает в диапазон 18—43 м². Наличие в выборке объектов недвижимости с большой жилой площадью (более 100 м²) приводит к отличию среднего арифметического от медианы. На диаграмме размаха эти значения не накрываются "ящиком с усами". По гистограмме можно охарактеризовать распределение значений как бимодальное.

kitchen_area — площадь кухни (м²)
Значения определены для 21 421 записи — это 90 % всех записей.
Значения определены с точностью до 0,01 м².
Минимальное значение составляет 1,3 м², максимальное — 112 м².
Среднее арифметическое значение равно 10,57 м², медиана — 9,1 м².
Первый, второй и третий квартили — близкие по значению величины. Почти у половины объектов недвижимости значение площади кухни попадает в диапазон 7—12 м². Наличие в выборке объектов недвижимости с большой площадью кухни (более 20 м²) приводит к отличию среднего арифметического от медианы. На диаграмме размаха эти значения не накрываются "ящиком с усами". По гистограмме можно охарактеризовать распределение значений как унимодальное с положительной ассиметрией пика.

ceiling_height — высота потолков (м)
Значения определены для 14 504 записей — это 61 % всех записей.
Значения определены с точностью до 0,01 м.
Минимальное значение составляет 1 м, максимальное — 100 м.
Среднее арифметическое значение равно 2,77 м, медиана — 2,65 м.
Первый, второй и третий квартили — близкие по значению величины. Не менее чем у трети объектов недвижимости значение высоты потолков попадает в диапазон 2,5—2,8 м. На диаграмме размаха большинство значений накрываются "ящиком с усами". Но в выборке присутствуют значения меньше наблюдаемого минимума и больше наблюдаемого максимума. Минимальное и максимальное значения представляются сомнительными, что свидетельствует о наличии ошибок в данных. По гистограмме нельзя охарактеризовать распределение значений, поскольку пик распределения достаточно узкий и существуют значения, сильно отличающиеся от среднего. Узость "ящика с усами" на диаграмме размаха свидетельствует о низком разбросе значений относительно своего среднего.

city_centers_nearest — расстояние до центра города Санкт-Петербурга (м)
Значения определены для 18 180 записей — это 77 % всех записей.
Значения определены с точностью до 1 м.
Минимальное значение составляет 181 м, максимальное — 65 968 м.
Среднее арифметическое значение равно 14 191,28 м, медиана — 13 098,5 м.
Первый, второй и третий квартили — близкие по значению величины. Расстояние от объекта недвижимости до центра города Санкт-Петербурга в 40 % записей попадает в диапазон 9—17 км. На гистограмме наблюдается наличие нескольких максимумов. "Ящик с усами" на диаграмме размаха не накрывает значения больше 30 км.

airports_nearest — расстояние до аэропорта Пулково (м)
Значения определены для 18 157 записей — это 77 % всех записей.
Значения определены с точностью до 1 м.
Минимальное значение составляет 0 м, максимальное — 84 869 м.
Среднее арифметическое значение равно 28 793,67 м, медиана — 26 726 м.
Первый, второй и третий квартили различаются между собой на 9 км. На гистограмме видно, что распределение значений широкое, с несколькими максимумами. На диаграмме размаха также наблюдается увеличенная ширина "ящика" с увеличенной длиной "усов". "Ящик с усами" не накрывает значения больше 70 км. Минимальное значение 0 м представляется сомнительным. Это свидетельствует о наличии ошибки в данных.

parks_nearest — расстояние до ближайшего парка (м)
Значения определены для 8079 записей — это 34 % всех записей.
Значения определены с точностью до 1 м.
Минимальное значение составляет 1 м, максимальное — 3190 м.
Среднее арифметическое значение равно 490,8 м, медиана — 455 м.
Первый, второй и третий квартили — близкие по значению величины. Расстояние от объекта недвижимости до ближайшего парка не менее чем в 15 % записей попадает в диапазон 280—620 м. Наличие в выборке объектов недвижимости, от которых до парка более 1200 м приводит к смещению среднего арифметического от медианы в большую сторону. Эти значения не накрываются "ящиком с усами" на диаграмме размаха. По гистограмме можно охарактеризовать распределение значений как унимодальное с практически отсутствующей ассиметрией пика. Минимальное значение 1 м представляется сомнительным. Это свидетельствует о наличии ошибки в данных.

ponds_nearest — расстояние до ближайшего водоёма (м)
Значения определены для 9110 записей — это 38 % всех записей.
Значения определены с точностью до 1 м.
Минимальное значение составляет 13 м, максимальное — 1344 м.
Среднее арифметическое значение равно 517,98 м, медиана — 502 м.
Первый, второй и третий квартили различаются между собой на 200 м. Среднее арифметическое совсем незначительно отличается от медианы. На гистограмме видно, что распределение значений широкое, с единственным максимумом. Все значения накрываются "ящиком с усами" на диаграмме размаха.

days_exposition — период размещения объявления
Значения определены для 20 518 записей — это 87 % всех записей.
Значения определены с точностью до 1 дня.
Минимальное значение составляет 1 день, максимальное — 1580 дней.
Медиана — 95 дней. Среднее арифметическое — 181 день.
Среднее арифметическое значительно отличается от медианы. Это является следствием наличия сильно отличающихся, больших значений в выборке. Третий квартиль сильнее отличается от медианы, чем первый квартиль. По гистограмме можно охарактеризовать распределение значений как экспоненциальное. На диаграмме размаха "ящик с усами" не накрывает значения больше 600 дней.

Признаки, измеряемые в порядковой шкале¶

In [19]:
columns = ['rooms', 'balcony', 'floor', 'floors_total',
           'parks_around_3000', 'ponds_around_3000', 'total_images']
In [20]:
data[columns].describe().round(2)
Out[20]:
rooms balcony floor floors_total parks_around_3000 ponds_around_3000 total_images
count 23699.00 12180.00 23699.00 23613.00 18181.00 18181.00 23699.00
mean 2.07 1.15 5.89 10.67 0.61 0.77 9.86
std 1.08 1.07 4.89 6.60 0.80 0.94 5.68
min 0.00 0.00 1.00 1.00 0.00 0.00 0.00
25% 1.00 0.00 2.00 5.00 0.00 0.00 6.00
50% 2.00 1.00 4.00 9.00 0.00 1.00 9.00
75% 3.00 2.00 8.00 16.00 1.00 1.00 14.00
max 19.00 5.00 33.00 60.00 3.00 3.00 50.00
In [21]:
for column in columns:
    graph(column)

rooms — общее количество комнат в квартире
Значения определены для всех записей.
Разница между уровнями значений — 1 комната.
Минимальное значение составляет 0 комнат, максимальное — 19 комнат.
Медиана — 2 комнаты.
Первый, второй и третий квартили — близкие по значению величины. Не менее чем у половины объектов недвижимости значение количества комнат находится в диапазоне 1—3. Большинство объектов недвижимости имеет не более 7 комнат — эти значения накрываются "ящиком с усами" на диаграмме размаха.

balcony — количество балконов
Значения определены для 12 180 записей — это 51 % всех записей.
Разница между уровнями значений — 1 балкон.
Минимальное значение составляет 0 балконов, максимальное — 5 балконов.
Медиана — 1 балкон.
Первый, второй и третий квартили — близкие по значению величины. Большинство объектов недвижимости имеет не более 2 балконов — это отчётливо видно на гистограмме.

floor — этаж, на котором находится объект
Значения определены для всех записей.
Разница между уровнями значений — 1 этаж.
Минимальное значение — 1-й этаж, максимальное — 33-й этаж.
Медиана — 4-й этаж.
Не менее половины всех объектов недвижимости расположены на этаже из диапазона 2—8-й этаж. Большинство объектов расположено не выше 17-го этажа — эти значения накрывает "ящик с усами" на диаграмме размаха.

floors_total — общее количество этажей в здании
Значения определены для 23 613 записей — это 99,6 % записей.
Разница между уровнями значений — 1 этаж.
Минимальное значение составляет 1 этаж, максимальное — 60 этажей.
Медиана — 9 этажей.
Не менее половины всех объектов недвижимости расположены в зданиях, этажность которых находится в диапазоне 5—16 этажей. Большинство всех зданий имеют этажность менее 30 этажей — эти значения накрывает "ящик с усами" на диаграмме размаха.

parks_around_3000 — число парков в радиусе 3 км
Значения определены для 18 181 записи — это 77 % записей.
Разница между уровнями значений — 1 парк.
Минимальное значение составляет 0 парков, максимальное — 3 парка.
Медиана — 0 парков.

ponds_around_3000 — число водоёмов в радиусе 3 км
Значения определены для 18 181 записи — это 77 % записей.
Разница между уровнями значений — 1 водоём.
Минимальное значение составляет 0 водоёмов, максимальное — 3 водоёма.
Медиана — 1 водоём.

total_images — количество фотографий квартиры в объявлении
Значения определены для всех записей.
Разница между уровнями значений — 1 фотография.
Минимальное значение составляет 0 фотографий, максимальное — 50 фотографий.
Медиана — 9 фотографий.
Первый, второй и третий квартили — близкие по значению величины. Не менее половины всех объектов недвижимости публикуются с фотографиями, количество которых находится в диапазоне 6—14 фотографий. В большинстве объявлений количество опубликованных фотографий не превышает 20.

Признаки, измеряемые в интервальной шкале, в номинальной шкале, в дихотомической шкале¶

In [22]:
data[['first_day_exposition', 'locality_name',
      'studio', 'open_plan', 'is_apartment']].describe()
Out[22]:
first_day_exposition locality_name studio open_plan is_apartment
count 23699 23650 23699 23699 2775
unique 1491 364 2 2 2
top 2018-02-01T00:00:00 Санкт-Петербург False False False
freq 368 15721 23550 23632 2725
In [23]:
data['first_day_exposition'].value_counts().head()
Out[23]:
first_day_exposition
2018-02-01T00:00:00    368
2017-11-10T00:00:00    240
2017-10-13T00:00:00    124
2017-09-27T00:00:00    111
2018-03-26T00:00:00     97
Name: count, dtype: int64
In [24]:
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(15, 6))
ax1.set_title('Диаграмма распределения и диаграмма размаха' +
              '\nколичества уникальных значений признака first_day_exposition')
ax1.hist(data['first_day_exposition'].value_counts(), bins=100)
ax1.tick_params(labelbottom=False)
ax1.set_ylabel('Частота')
ax2.boxplot(data['first_day_exposition'].value_counts(), vert=False)
ax2.tick_params(left=False, labelleft=False)
ax2.set_xlabel('Количество уникальных значений признака first_day_exposition')
plt.show()

first_day_exposition — дата публикации
Значения определены для всех записей.
Мода — 1 февраля 2018 года, её частота — 368.
Минимальное число публикаций в день — 1, максимальное — 368. За наблюдаемый период времени для большинства дней количество публикуемых объявлений в день не превышало 50.

In [25]:
data['locality_name'].value_counts().head()
Out[25]:
locality_name
Санкт-Петербург    15721
посёлок Мурино       522
посёлок Шушары       440
Всеволожск           398
Пушкин               369
Name: count, dtype: int64
In [26]:
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(15, 6))
ax1.set_title('Диаграмма распределения и диаграмма размаха' +
              '\nколичества уникальных значений признака locality_name')
ax1.hist(data['locality_name'].value_counts(), bins=100)
ax1.tick_params(labelbottom=False)
ax1.set_ylabel('Частота')
ax2.boxplot(data['locality_name'].value_counts(), vert=False)
ax2.tick_params(left=False, labelleft=False)
ax2.set_xlabel('Количество уникальных значений признака locality_name')
plt.show()

locality_name — название населённого пункта
Значения определены для 23 650 записей — это 99,8 % всех записей.
Мода — город Санкт-Петербург, её частота — 15 721.
Минимальное количество объявлений, приходящихся на один населённый пункт, — 1, максимальное — 15 721.
В большинстве населённых пунктах расположено по 1 объекту недвижимости, объявления о которых были размещены на сервисе.

In [27]:
columns = ['studio', 'open_plan', 'is_apartment']
In [28]:
for column in columns:
    plt.figure(figsize=(5, 3))
    plt.title(f'Гистограма распределения\nзначений признака {column}')
    data[column].value_counts().plot(kind='bar', rot=0)
    plt.xlabel(f'Значения признака {column}')
    plt.ylabel('Частота')
    plt.show()

studio — квартира-студия
Значения определены для всех записей.
Мода — объект недвижимости не является квартирой-студией, её частота — 23 550.

open_plan — открытая планировка
Значения определены для всех записей.
Мода — в объекте недвижимости нет открытой планировки, её частота — 23 632.

is_apartment — апартаменты
Значения определены для 2775 записей — это 12 % всех записей.
Мода — объект недвижимости не является апартаментами, её частота — 2725.

Промежуточный вывод

  • В наборе данных имеются признаки, измеряемые в различных количественных и качественных шкалах.
  • В наборе данных наблюдаются аномальные значения, противоречащие физической природе данных, вложенные сведения, пропуски в данных, изменённые типы данных.
  • Необходимо провести предварительную обработку данных:
    • выявить и отредактировать/удалить сведения, содержащие аномальные значения, ошибки в данных,
    • выявить несогласующиеся значения связанных признаков,
    • извлечь вложенные сведения,
    • заполнить пропуски подходящими значениями, где это возможно, в противном случае заполнить фиктивными значениями-метками,
    • привести типы данных к требуемым в соответствии с природой признака и его шкалой,
    • проверить наличие дубликатов: полных и частичных, удалить дубли,
    • обогатить данные: сгенерировать дополнительные признаки, провести категоризацию данных.

Предобработка данных¶

Обработка текстовых значений и извлечение вложенных сведений¶

Прежде всего произведём обработку текстовых значений.

Признак locality_name содержит в своих значениях вложенные сведения: в них указаны не только наименования населённых пунктов, но и их тип. Населённые пункты, для которых не указан в явном виде тип, относятся к типу "город".

In [29]:
data['locality_name'].sort_values().unique()
Out[29]:
array(['Бокситогорск', 'Волосово', 'Волхов', 'Всеволожск', 'Выборг',
       'Высоцк', 'Гатчина', 'Зеленогорск', 'Ивангород', 'Каменногорск',
       'Кингисепп', 'Кириши', 'Кировск', 'Колпино', 'Коммунар',
       'Красное Село', 'Кронштадт', 'Кудрово', 'Лодейное Поле',
       'Ломоносов', 'Луга', 'Любань', 'Мурино', 'Никольское',
       'Новая Ладога', 'Отрадное', 'Павловск', 'Петергоф', 'Пикалёво',
       'Подпорожье', 'Приморск', 'Приозерск', 'Пушкин', 'Санкт-Петербург',
       'Светогорск', 'Сертолово', 'Сестрорецк', 'Сланцы', 'Сосновый Бор',
       'Сясьстрой', 'Тихвин', 'Тосно', 'Шлиссельбург',
       'городской поселок Большая Ижора', 'городской поселок Янино-1',
       'городской посёлок Будогощь', 'городской посёлок Виллози',
       'городской посёлок Лесогорский', 'городской посёлок Мга',
       'городской посёлок Назия', 'городской посёлок Новоселье',
       'городской посёлок Павлово', 'городской посёлок Рощино',
       'городской посёлок Свирьстрой', 'городской посёлок Советский',
       'городской посёлок Фёдоровское', 'городской посёлок Янино-1',
       'деревня Агалатово', 'деревня Аро', 'деревня Батово',
       'деревня Бегуницы', 'деревня Белогорка', 'деревня Большая Вруда',
       'деревня Большая Пустомержа', 'деревня Большие Колпаны',
       'деревня Большое Рейзино', 'деревня Большой Сабск', 'деревня Бор',
       'деревня Борисова Грива', 'деревня Ваганово', 'деревня Вартемяги',
       'деревня Вахнова Кара', 'деревня Выскатка', 'деревня Гарболово',
       'деревня Глинка', 'деревня Горбунки', 'деревня Гостилицы',
       'деревня Заклинье', 'деревня Заневка', 'деревня Зимитицы',
       'деревня Извара', 'деревня Иссад', 'деревня Калитино',
       'деревня Кальтино', 'деревня Камышовка', 'деревня Каськово',
       'деревня Келози', 'деревня Кипень', 'деревня Кисельня',
       'деревня Колтуши', 'деревня Коркино', 'деревня Котлы',
       'деревня Кривко', 'деревня Кудрово', 'деревня Кузьмолово',
       'деревня Курковицы', 'деревня Куровицы', 'деревня Куттузи',
       'деревня Лаврики', 'деревня Лаголово', 'деревня Лампово',
       'деревня Лесколово', 'деревня Лопухинка', 'деревня Лупполово',
       'деревня Малая Романовка', 'деревня Малое Верево',
       'деревня Малое Карлино', 'деревня Малые Колпаны',
       'деревня Мануйлово', 'деревня Меньково', 'деревня Мины',
       'деревня Мистолово', 'деревня Ненимяки', 'деревня Нижние Осельки',
       'деревня Нижняя', 'деревня Низино', 'деревня Новое Девяткино',
       'деревня Новолисино', 'деревня Нурма', 'деревня Оржицы',
       'деревня Парицы', 'деревня Пельгора', 'деревня Пеники',
       'деревня Пижма', 'деревня Пикколово', 'деревня Пудомяги',
       'деревня Пустынка', 'деревня Пчева', 'деревня Рабитицы',
       'деревня Разбегаево', 'деревня Раздолье', 'деревня Разметелево',
       'деревня Рапполово', 'деревня Реброво', 'деревня Русско',
       'деревня Сижно', 'деревня Снегирёвка', 'деревня Старая',
       'деревня Старая Пустошь', 'деревня Старое Хинколово',
       'деревня Старополье', 'деревня Старосиверская',
       'деревня Старые Бегуницы', 'деревня Суоранда',
       'деревня Сяськелево', 'деревня Тарасово', 'деревня Терпилицы',
       'деревня Тихковицы', 'деревня Тойворово', 'деревня Торосово',
       'деревня Торошковичи', 'деревня Трубников Бор',
       'деревня Фалилеево', 'деревня Фёдоровское', 'деревня Хапо-Ое',
       'деревня Хязельки', 'деревня Чудской Бор', 'деревня Шпаньково',
       'деревня Щеглово', 'деревня Юкки', 'деревня Ялгино',
       'деревня Яльгелево', 'деревня Ям-Тесово',
       'коттеджный поселок Кивеннапа Север', 'коттеджный поселок Счастье',
       'коттеджный посёлок Лесное', 'поселок Аннино', 'поселок Барышево',
       'поселок Бугры', 'поселок Возрождение', 'поселок Войсковицы',
       'поселок Володарское', 'поселок Гаврилово', 'поселок Гарболово',
       'поселок Гладкое', 'поселок Глажево', 'поселок Глебычево',
       'поселок Гончарово', 'поселок Громово', 'поселок Дружноселье',
       'поселок Елизаветино', 'поселок Жилгородок', 'поселок Жилпосёлок',
       'поселок Житково', 'поселок Заводской', 'поселок Запорожское',
       'поселок Зимитицы', 'поселок Ильичёво', 'поселок Калитино',
       'поселок Каложицы', 'поселок Кингисеппский', 'поселок Кирпичное',
       'поселок Кобралово', 'поселок Кобринское', 'поселок Коммунары',
       'поселок Коробицыно', 'поселок Котельский',
       'поселок Красная Долина', 'поселок Красносельское',
       'поселок Лесное', 'поселок Лисий Нос', 'поселок Лукаши',
       'поселок Любань', 'поселок Мельниково', 'поселок Мичуринское',
       'поселок Молодцово', 'поселок Мурино', 'поселок Новый Свет',
       'поселок Новый Учхоз', 'поселок Оредеж',
       'поселок Пансионат Зелёный Бор', 'поселок Первомайское',
       'поселок Перово', 'поселок Петровское', 'поселок Победа',
       'поселок Поляны', 'поселок Почап', 'поселок Починок',
       'поселок Пушное', 'поселок Пчевжа', 'поселок Рабитицы',
       'поселок Романовка', 'поселок Ромашки', 'поселок Рябово',
       'поселок Севастьяново', 'поселок Селезнёво', 'поселок Сельцо',
       'поселок Семиозерье', 'поселок Семрино', 'поселок Серебрянский',
       'поселок Совхозный', 'поселок Старая Малукса',
       'поселок Стеклянный', 'поселок Сумино', 'поселок Суходолье',
       'поселок Тельмана', 'поселок Терволово', 'поселок Торковичи',
       'поселок Тёсово-4', 'поселок Углово', 'поселок Усть-Луга',
       'поселок Ушаки', 'поселок Цвелодубово', 'поселок Цвылёво',
       'поселок городского типа Большая Ижора',
       'поселок городского типа Вырица',
       'поселок городского типа Дружная Горка',
       'поселок городского типа Дубровка',
       'поселок городского типа Ефимовский',
       'поселок городского типа Кондратьево',
       'поселок городского типа Красный Бор',
       'поселок городского типа Кузьмоловский',
       'поселок городского типа Лебяжье',
       'поселок городского типа Лесогорский',
       'поселок городского типа Назия',
       'поселок городского типа Никольский',
       'поселок городского типа Приладожский',
       'поселок городского типа Рахья', 'поселок городского типа Рощино',
       'поселок городского типа Рябово',
       'поселок городского типа Синявино',
       'поселок городского типа Советский',
       'поселок городского типа Токсово',
       'поселок городского типа Форносово',
       'поселок городского типа имени Свердлова',
       'поселок станции Вещево', 'поселок станции Корнево',
       'поселок станции Лужайка', 'поселок станции Приветнинское',
       'посёлок Александровская', 'посёлок Алексеевка', 'посёлок Аннино',
       'посёлок Белоостров', 'посёлок Бугры', 'посёлок Возрождение',
       'посёлок Войскорово', 'посёлок Высокоключевой',
       'посёлок Гаврилово', 'посёлок Дзержинского', 'посёлок Жилгородок',
       'посёлок Ильичёво', 'посёлок Кикерино', 'посёлок Кобралово',
       'посёлок Коробицыно', 'посёлок Левашово', 'посёлок Ленинское',
       'посёлок Лисий Нос', 'посёлок Мельниково', 'посёлок Металлострой',
       'посёлок Мичуринское', 'посёлок Молодёжное', 'посёлок Мурино',
       'посёлок Мыза-Ивановка', 'посёлок Новогорелово',
       'посёлок Новый Свет', 'посёлок Пансионат Зелёный Бор',
       'посёлок Парголово', 'посёлок Перово', 'посёлок Песочный',
       'посёлок Петро-Славянка', 'посёлок Петровское',
       'посёлок Платформа 69-й километр', 'посёлок Плодовое',
       'посёлок Плоское', 'посёлок Победа', 'посёлок Поляны',
       'посёлок Понтонный', 'посёлок Пригородный', 'посёлок Пудость',
       'посёлок Репино', 'посёлок Ропша', 'посёлок Сапёрное',
       'посёлок Сапёрный', 'посёлок Сосново', 'посёлок Старая Малукса',
       'посёлок Стеклянный', 'посёлок Стрельна', 'посёлок Суйда',
       'посёлок Сумино', 'посёлок Тельмана', 'посёлок Терволово',
       'посёлок Торфяное', 'посёлок Усть-Ижора', 'посёлок Усть-Луга',
       'посёлок Форт Красная Горка', 'посёлок Шугозеро', 'посёлок Шушары',
       'посёлок Щеглово', 'посёлок городского типа Важины',
       'посёлок городского типа Вознесенье',
       'посёлок городского типа Вырица',
       'посёлок городского типа Красный Бор',
       'посёлок городского типа Кузнечное',
       'посёлок городского типа Кузьмоловский',
       'посёлок городского типа Лебяжье', 'посёлок городского типа Мга',
       'посёлок городского типа Павлово',
       'посёлок городского типа Рощино', 'посёлок городского типа Рябово',
       'посёлок городского типа Сиверский',
       'посёлок городского типа Тайцы', 'посёлок городского типа Токсово',
       'посёлок городского типа Ульяновка',
       'посёлок городского типа Форносово',
       'посёлок городского типа имени Морозова',
       'посёлок городского типа имени Свердлова',
       'посёлок при железнодорожной станции Вещево',
       'посёлок при железнодорожной станции Приветнинское',
       'посёлок станции Громово', 'посёлок станции Свирь',
       'садоводческое некоммерческое товарищество Лесная Поляна',
       'садовое товарищество Новая Ропша',
       'садовое товарищество Приладожский', 'садовое товарищество Рахья',
       'садовое товарищество Садко', 'село Копорье', 'село Никольское',
       'село Павлово', 'село Паша', 'село Путилово', 'село Рождествено',
       'село Русско-Высоцкое', 'село Старая Ладога', 'село Шум', nan],
      dtype=object)

В обозначениях типа населённого пункта встречаются слова, различающиеся буквами е и ё. Необходимо привести названия типов населённых пунктов к единому формату, а затем выделить их в отдельный признак — locality_type.

In [30]:
# Корректировка текстовых значений.
data['locality_name'] = data['locality_name'].replace('поселок', 'посёлок', regex=True)

# Названия типов населённых пунктов.
locality_type = ['посёлок',
                 'посёлок городского типа',
                 'городской посёлок',
                 'посёлок при железнодорожной станции',
                 'посёлок станции',
                 'коттеджный посёлок',
                 'деревня',
                 'село',
                 'садоводческое некоммерческое товарищество',
                 'садовое товарищество']

# Извлечение названия типа населённого пункта из значений признака locality_name.
for i in data[data['locality_name'].notna()].index:
    for j in range(len(locality_type)):
        if locality_type[j] in data.loc[i, 'locality_name']:
            data.loc[i, 'locality_type'] = locality_type[j]

# Присвоение значения 'город' в качестве типа населённого пункта для тех записей,
# у которых в значениях признака locality_name тип не указан в явном виде.
for i in data[data['locality_name'].notna() & data['locality_type'].isna()].index:
    data.loc[i, 'locality_type'] = 'город'
In [31]:
data[['locality_name', 'locality_type']].sample(7)
Out[31]:
locality_name locality_type
20529 Санкт-Петербург город
20467 Кудрово город
2804 деревня Кудрово деревня
27 Санкт-Петербург город
899 деревня Кудрово деревня
13227 Всеволожск город
4046 Санкт-Петербург город
In [32]:
data['locality_type'].unique()
Out[32]:
array(['город', 'посёлок', 'городской посёлок', 'деревня',
       'посёлок городского типа', 'садовое товарищество', 'село', nan,
       'посёлок станции', 'садоводческое некоммерческое товарищество',
       'посёлок при железнодорожной станции', 'коттеджный посёлок'],
      dtype=object)

Взаимно однозначное соответствие между значениями признака locality_type и значениями признака locality_name установлено верно. Список уникальных значений содержит только те названия типов, которые были заданы. Поскольку признак locality_name содержит пропуски, то и признак locality_type содержит пропуски в тех же записях.

В соответствии с законом "Об административно-территориальном устройстве Ленинградской области и порядке его изменения" наименования "городской посёлок" и "посёлок городского типа" являются синонимами. Кроме того, в соответствии с законом "посёлок станции" именуется как "посёлок при железнодорожной станции".
Заменим "посёлок городского типа" на "городской посёлок", а "посёлок станции" на "посёлок при железнодорожной станции".

In [33]:
data.loc[data['locality_type'] == 'посёлок городского типа',
         'locality_type'] = 'городской посёлок'
data.loc[data['locality_type'] == 'посёлок станции',
         'locality_type'] = 'посёлок при железнодорожной станции'

data['locality_type'].sort_values().unique()
Out[33]:
array(['город', 'городской посёлок', 'деревня', 'коттеджный посёлок',
       'посёлок', 'посёлок при железнодорожной станции',
       'садоводческое некоммерческое товарищество',
       'садовое товарищество', 'село', nan], dtype=object)

Теперь уберём наиманование типа населённого пункта из признака locality_name.

In [34]:
locality_type = ['посёлок городского типа',
                 'городской посёлок',
                 'посёлок при железнодорожной станции',
                 'посёлок станции',
                 'коттеджный посёлок',
                 'посёлок',
                 'деревня',
                 'село',
                 'садоводческое некоммерческое товарищество',
                 'садовое товарищество']

for type_name in locality_type:
    data['locality_name'] = data['locality_name'].replace(type_name, '',
                                                          regex=True).str.strip()
In [35]:
sorted(data[data['locality_name'].notna()]['locality_name'].unique())
Out[35]:
['Агалатово',
 'Александровская',
 'Алексеевка',
 'Аннино',
 'Аро',
 'Барышево',
 'Батово',
 'Бегуницы',
 'Белогорка',
 'Белоостров',
 'Бокситогорск',
 'Большая Вруда',
 'Большая Ижора',
 'Большая Пустомержа',
 'Большие Колпаны',
 'Большое Рейзино',
 'Большой Сабск',
 'Бор',
 'Борисова Грива',
 'Бугры',
 'Будогощь',
 'Ваганово',
 'Важины',
 'Вартемяги',
 'Вахнова Кара',
 'Вещево',
 'Виллози',
 'Вознесенье',
 'Возрождение',
 'Войсковицы',
 'Войскорово',
 'Володарское',
 'Волосово',
 'Волхов',
 'Всеволожск',
 'Выборг',
 'Вырица',
 'Выскатка',
 'Высокоключевой',
 'Высоцк',
 'Гаврилово',
 'Гарболово',
 'Гатчина',
 'Гладкое',
 'Глажево',
 'Глебычево',
 'Глинка',
 'Гончарово',
 'Горбунки',
 'Гостилицы',
 'Громово',
 'Дзержинского',
 'Дружная Горка',
 'Дружноселье',
 'Дубровка',
 'Елизаветино',
 'Ефимовский',
 'Жил',
 'Жилгородок',
 'Житково',
 'Заводской',
 'Заклинье',
 'Заневка',
 'Запорожское',
 'Зеленогорск',
 'Зимитицы',
 'Ивангород',
 'Извара',
 'Ильичёво',
 'Иссад',
 'Калитино',
 'Каложицы',
 'Кальтино',
 'Каменногорск',
 'Камышовка',
 'Каськово',
 'Келози',
 'Кивеннапа Север',
 'Кикерино',
 'Кингисепп',
 'Кингисеппский',
 'Кипень',
 'Кириши',
 'Кировск',
 'Кирпичное',
 'Кисельня',
 'Кобралово',
 'Кобринское',
 'Колпино',
 'Колтуши',
 'Коммунар',
 'Коммунары',
 'Кондратьево',
 'Копорье',
 'Коркино',
 'Корнево',
 'Коробицыно',
 'Котельский',
 'Котлы',
 'Красная Долина',
 'Красное Село',
 'Красносельское',
 'Красный Бор',
 'Кривко',
 'Кронштадт',
 'Кудрово',
 'Кузнечное',
 'Кузьмолово',
 'Кузьмоловский',
 'Курковицы',
 'Куровицы',
 'Куттузи',
 'Лаврики',
 'Лаголово',
 'Лампово',
 'Лебяжье',
 'Левашово',
 'Ленинское',
 'Лесколово',
 'Лесная Поляна',
 'Лесное',
 'Лесогорский',
 'Лисий Нос',
 'Лодейное Поле',
 'Ломоносов',
 'Лопухинка',
 'Луга',
 'Лужайка',
 'Лукаши',
 'Лупполово',
 'Любань',
 'Малая Романовка',
 'Малое Верево',
 'Малое Карлино',
 'Малые Колпаны',
 'Мануйлово',
 'Мга',
 'Мельниково',
 'Меньково',
 'Металлострой',
 'Мины',
 'Мистолово',
 'Мичуринское',
 'Молодцово',
 'Молодёжное',
 'Мурино',
 'Мыза-Ивановка',
 'Назия',
 'Ненимяки',
 'Нижние Осельки',
 'Нижняя',
 'Низино',
 'Никольский',
 'Никольское',
 'Новая Ладога',
 'Новая Ропша',
 'Новогорелово',
 'Новое Девяткино',
 'Новолисино',
 'Новоселье',
 'Новый Свет',
 'Новый Учхоз',
 'Нурма',
 'Оредеж',
 'Оржицы',
 'Отрадное',
 'Павлово',
 'Павловск',
 'Пансионат Зелёный Бор',
 'Парголово',
 'Парицы',
 'Паша',
 'Пельгора',
 'Пеники',
 'Первомайское',
 'Перово',
 'Песочный',
 'Петергоф',
 'Петро-Славянка',
 'Петровское',
 'Пижма',
 'Пикалёво',
 'Пикколово',
 'Платформа 69-й километр',
 'Плодовое',
 'Плоское',
 'Победа',
 'Подпорожье',
 'Поляны',
 'Понтонный',
 'Почап',
 'Починок',
 'Приветнинское',
 'Пригородный',
 'Приладожский',
 'Приморск',
 'Приозерск',
 'Пудомяги',
 'Пудость',
 'Пустынка',
 'Путилово',
 'Пушкин',
 'Пушное',
 'Пчева',
 'Пчевжа',
 'Рабитицы',
 'Разбегаево',
 'Раздолье',
 'Разметелево',
 'Рапполово',
 'Рахья',
 'Реброво',
 'Репино',
 'Рождествено',
 'Романовка',
 'Ромашки',
 'Ропша',
 'Рощино',
 'Русско',
 'Русско-Высоцкое',
 'Рябово',
 'Садко',
 'Санкт-Петербург',
 'Сапёрное',
 'Сапёрный',
 'Светогорск',
 'Свирь',
 'Свирьстрой',
 'Севастьяново',
 'Селезнёво',
 'Сельцо',
 'Семиозерье',
 'Семрино',
 'Серебрянский',
 'Сертолово',
 'Сестрорецк',
 'Сиверский',
 'Сижно',
 'Синявино',
 'Сланцы',
 'Снегирёвка',
 'Советский',
 'Совхозный',
 'Сосново',
 'Сосновый Бор',
 'Старая',
 'Старая Ладога',
 'Старая Малукса',
 'Старая Пустошь',
 'Старое Хинколово',
 'Старополье',
 'Старосиверская',
 'Старые Бегуницы',
 'Стеклянный',
 'Стрельна',
 'Суйда',
 'Сумино',
 'Суоранда',
 'Суходолье',
 'Счастье',
 'Сяськелево',
 'Сясьстрой',
 'Тайцы',
 'Тарасово',
 'Тельмана',
 'Терволово',
 'Терпилицы',
 'Тихвин',
 'Тихковицы',
 'Тойворово',
 'Токсово',
 'Торковичи',
 'Торосово',
 'Торошковичи',
 'Торфяное',
 'Тосно',
 'Трубников Бор',
 'Тёсово-4',
 'Углово',
 'Ульяновка',
 'Усть-Ижора',
 'Усть-Луга',
 'Ушаки',
 'Фалилеево',
 'Форносово',
 'Форт Красная Горка',
 'Фёдоровское',
 'Хапо-Ое',
 'Хязельки',
 'Цвелодубово',
 'Цвылёво',
 'Чудской Бор',
 'Шлиссельбург',
 'Шпаньково',
 'Шугозеро',
 'Шум',
 'Шушары',
 'Щеглово',
 'Юкки',
 'Ялгино',
 'Яльгелево',
 'Ям-Тесово',
 'Янино-1',
 'имени Морозова',
 'имени Свердлова']

Тип населённого пункта "коттеджный посёлок" отсутствует в российском законодательстве. Коттеджный посёлок Кивеннапа Север является частью посёлка Первомайское. Коттеджные посёлки Счастье и Лесное встречаются в Ленинградской области более одного раза. Установить однозначно их местоположение не представляется возможным. Поэтому записи об объектах в этих посёлках удаляем.

In [36]:
data.loc[data['locality_name'] == 'Кивеннапа Север',
         ['locality_name', 'locality_type']] = ['Первомайское', 'посёлок']

data.drop(index=data[data['locality_type'] == 'коттеджный посёлок'].index,
          inplace=True)

data['locality_type'].sort_values().unique()
Out[36]:
array(['город', 'городской посёлок', 'деревня', 'посёлок',
       'посёлок при железнодорожной станции',
       'садоводческое некоммерческое товарищество',
       'садовое товарищество', 'село', nan], dtype=object)

Садоводческое некоммерческое товарищество (СНТ) является некоммерческой организацией, а не типом населённого пункта. Садовое товарищество правильней именовать садоводческим некоммерческим товариществом.

Садовое товарищество Приладожский — ошибочное наименование, поскольку в Ленинградской области есть садоводческое некоммерческое товарищество Приладожское, которое расположено в городском посёлке Приладожский. СНТ Рахья находится в городском посёлке Рахья. СНТ Новая Ропша находится в посёлке Ропша. Произведём соответствующие замены.

СНТ Садко и СНТ Лесная Поляна встречаются в Ленинградской области более одного раза. Поэтому записи об этих объектах удаляем.

In [37]:
data.loc[(data['locality_name'] == 'Приладожский') &
         (data['locality_type'] == 'садовое товарищество'),
         'locality_type'] = 'городской посёлок'
data.loc[(data['locality_name'] == 'Рахья') &
         (data['locality_type'] == 'садовое товарищество'),
         'locality_type'] = 'городской посёлок'
data.loc[(data['locality_name'] == 'Новая Ропша') &
         (data['locality_type'] == 'садовое товарищество'),
         ['locality_name', 'locality_type']] = ['Ропша', 'посёлок']

data.drop(index=data[(data['locality_name'] == 'Садко') &
                     (data['locality_type'] == 'садовое товарищество')].index,
          inplace=True)
data.drop(index=data[(data['locality_name'] == 'Лесная Поляна') &
                     (data['locality_type'] == 'садоводческое некоммерческое товарищество')].index,
          inplace=True)

data['locality_type'].sort_values().unique()
Out[37]:
array(['город', 'городской посёлок', 'деревня', 'посёлок',
       'посёлок при железнодорожной станции', 'село', nan], dtype=object)

Гарболово является деревней, а не посёлком. Поэтому заменим тип населённого пункта "посёлок" на "деревня" у населённого пункта Гарболово.

In [38]:
data.loc[data['locality_name'] == 'Гарболово', 'locality_type'] = 'деревня'
data.loc[data['locality_name'] == 'Гарболово', 'locality_type'].unique()
Out[38]:
array(['деревня'], dtype=object)

Кондратьево является посёлком, а не городским посёлком. Поэтому заменим тип населённого пункта.

In [39]:
data.loc[data['locality_name'] == 'Кондратьево', 'locality_type'] = 'посёлок'
data.loc[data['locality_name'] == 'Кондратьево', 'locality_type'].unique()
Out[39]:
array(['посёлок'], dtype=object)

Посёлка Жил не существует. Вероятно, это посёлок Жилгородок. Произведём корректировку наименования населённого пункта.

In [40]:
data.loc[data['locality_name'] == 'Жил', 'locality_name'] = 'Жилгородок'
len(data.loc[data['locality_name'] == 'Жил'])
Out[40]:
0

Посёлок Почап является деревней. Поэтому заменим тип населённого пункта.

In [41]:
data.loc[data['locality_name'] == 'Почап', 'locality_type'] = 'деревня'
data.loc[data['locality_name'] == 'Почап', 'locality_type'].unique()
Out[41]:
array(['деревня'], dtype=object)
In [42]:
data.isna().sum().sort_values()
Out[42]:
total_images                0
studio                      0
floor                       0
rooms                       0
open_plan                   0
total_area                  0
last_price                  0
first_day_exposition        0
locality_type              49
locality_name              49
floors_total               86
living_area              1903
kitchen_area             2277
days_exposition          3181
ponds_around_3000        5514
parks_around_3000        5514
city_centers_nearest     5515
airports_nearest         5538
ceiling_height           9192
balcony                 11517
ponds_nearest           14585
parks_nearest           15616
is_apartment            20922
dtype: int64
  • Признак locality_name теперь содержит только наименования населённых пунктов без указания на их типы. Все значения признака являются уникальными.
  • Названия всех типов населённых пунктов теперь выделены в отдельный признак locality_type.

Описание данных признака locality_type

In [43]:
data['locality_type'].describe()
Out[43]:
count     23646
unique        6
top       город
freq      20008
Name: locality_type, dtype: object
In [44]:
data['locality_type'].value_counts()
Out[44]:
locality_type
город                                  20008
посёлок                                 2090
деревня                                  950
городской посёлок                        551
село                                      32
посёлок при железнодорожной станции       15
Name: count, dtype: int64
In [45]:
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(15, 6))
ax1.set_title('Диаграмма распределения и диаграмма размаха' +
              '\nколичества уникальных значений признака locality_type')
ax1.hist(data['locality_type'].value_counts(), bins=100)
ax1.tick_params(labelbottom=False)
ax1.set_ylabel('Частота')
ax2.boxplot(data['locality_type'].value_counts(), vert=False)
ax2.tick_params(left=False, labelleft=False)
ax2.set_xlabel('Количество уникальных значений признака locality_type')
plt.show()

locality_type — тип населённого пункта
Признак является категориальным, номинальным.
Шкала измерения признака: номинальная шкала.
Значения определены для 23 646 записей — это 99,8 % всех записей.
Мода — город, её частота — 20 008.
Минимальное количество объявлений, приходящихся на один тип населённого пункта, — 15, максимальное — 20 008.
Все объекты расположены в населённых пунктах 5 типов. Наибольшее количество объектов недвижимости приходится на города. Следующий по распространённости тип населённого пункта — посёлок — на порядок реже встречается в наборе данных.

Обработка аномальных и несогласованных значений¶

Жилая площадь¶

Количество значащих цифр

Особенность хранения десятичных чисел в памяти компьютера приводит к появлению после запятой лишних, незначащих цифр. Поскольку значения признака определены с точностью до 0,01 м², необходимо округлить значения до двух знаков после запятой.

In [46]:
data['living_area'].sort_values().unique()
Out[46]:
array([  2.      ,   3.      ,   5.      ,   5.4     ,   6.      ,
         6.5     ,   8.      ,   8.3     ,   8.4     ,   8.5     ,
         8.9     ,   9.      ,   9.1     ,   9.8     ,  10.      ,
        10.08    ,  10.3     ,  10.4     ,  10.5     ,  10.52    ,
        10.55    ,  10.6     ,  10.7     ,  10.76    ,  10.8     ,
        10.9     ,  10.93    ,  10.94    ,  11.      ,  11.1     ,
        11.15    ,  11.2     ,  11.3     ,  11.38    ,  11.4     ,
        11.47    ,  11.5     ,  11.6     ,  11.7     ,  11.79    ,
        11.88    ,  11.9     ,  11.99    ,  12.      ,  12.08    ,
        12.1     ,  12.18    ,  12.2     ,  12.28    ,  12.3     ,
        12.5     ,  12.6     ,  12.7     ,  12.71    ,  12.79    ,
        12.8     ,  12.81    ,  12.9     ,  13.      ,  13.05    ,
        13.09    ,  13.1     ,  13.15    ,  13.2     ,  13.27    ,
        13.3     ,  13.32    ,  13.34    ,  13.37    ,  13.4     ,
        13.46    ,  13.5     ,  13.54    ,  13.56    ,  13.59    ,
        13.6     ,  13.62    ,  13.66    ,  13.7     ,  13.73    ,
        13.76    ,  13.79    ,  13.8     ,  13.82    ,  13.89    ,
        13.9     ,  13.92    ,  14.      ,  14.01    ,  14.02    ,
        14.03    ,  14.06    ,  14.08    ,  14.1     ,  14.11    ,
        14.16    ,  14.17    ,  14.19    ,  14.2     ,  14.22    ,
        14.23    ,  14.25    ,  14.28    ,  14.3     ,  14.31    ,
        14.35    ,  14.37    ,  14.38    ,  14.39    ,  14.4     ,
        14.41    ,  14.45    ,  14.46    ,  14.47    ,  14.5     ,
        14.51    ,  14.55    ,  14.56    ,  14.57    ,  14.58    ,
        14.59    ,  14.6     ,  14.62    ,  14.64    ,  14.65    ,
        14.69    ,  14.7     ,  14.71    ,  14.73    ,  14.74    ,
        14.77    ,  14.8     ,  14.85    ,  14.89    ,  14.9     ,
        14.91    ,  14.92    ,  14.95    ,  15.      ,  15.01    ,
        15.02    ,  15.03    ,  15.04    ,  15.05    ,  15.06    ,
        15.07    ,  15.08    ,  15.1     ,  15.11    ,  15.12    ,
        15.13    ,  15.15    ,  15.16    ,  15.18    ,  15.2     ,
        15.25    ,  15.26    ,  15.3     ,  15.31    ,  15.32    ,
        15.33    ,  15.34    ,  15.35    ,  15.36    ,  15.37    ,
        15.38    ,  15.4     ,  15.41    ,  15.42    ,  15.43    ,
        15.45    ,  15.46    ,  15.5     ,  15.53    ,  15.54    ,
        15.55    ,  15.58    ,  15.6     ,  15.61    ,  15.62    ,
        15.64    ,  15.65    ,  15.66    ,  15.7     ,  15.71    ,
        15.72    ,  15.77    ,  15.78    ,  15.79    ,  15.8     ,
        15.82    ,  15.85    ,  15.86    ,  15.88    ,  15.89    ,
        15.9     ,  15.91    ,  15.92    ,  15.93    ,  15.96    ,
        16.      ,  16.04    ,  16.06    ,  16.07    ,  16.08    ,
        16.09    ,  16.1     ,  16.11    ,  16.12    ,  16.15    ,
        16.16    ,  16.18    ,  16.2     ,  16.22    ,  16.26    ,
        16.29    ,  16.3     ,  16.31    ,  16.32    ,  16.4     ,
        16.41    ,  16.42    ,  16.47    ,  16.5     ,  16.51    ,
        16.52    ,  16.55    ,  16.58    ,  16.59    ,  16.6     ,
        16.61    ,  16.62    ,  16.63    ,  16.66    ,  16.68    ,
        16.69    ,  16.7     ,  16.71    ,  16.72    ,  16.74    ,
        16.76    ,  16.8     ,  16.83    ,  16.84    ,  16.88    ,
        16.9     ,  16.91    ,  16.92    ,  16.93    ,  16.94    ,
        16.95    ,  16.96    ,  16.97    ,  16.98    ,  17.      ,
        17.01    ,  17.03    ,  17.04    ,  17.05    ,  17.07    ,
        17.08    ,  17.1     ,  17.11    ,  17.12    ,  17.14    ,
        17.19    ,  17.2     ,  17.22    ,  17.25    ,  17.26    ,
        17.27    ,  17.3     ,  17.33    ,  17.34    ,  17.35    ,
        17.36    ,  17.38    ,  17.4     ,  17.43    ,  17.45    ,
        17.48    ,  17.49    ,  17.5     ,  17.5115  ,  17.53    ,
        17.6     ,  17.62    ,  17.65    ,  17.66    ,  17.7     ,
        17.71    ,  17.73    ,  17.78    ,  17.8     ,  17.82    ,
        17.83    ,  17.84    ,  17.85    ,  17.87    ,  17.9     ,
        17.92    ,  17.93    ,  17.95    ,  17.97    ,  18.      ,
        18.02    ,  18.03    ,  18.04    ,  18.08    ,  18.09    ,
        18.1     ,  18.11    ,  18.12    ,  18.14    ,  18.15    ,
        18.16    ,  18.19    ,  18.2     ,  18.23    ,  18.28    ,
        18.3     ,  18.33    ,  18.34    ,  18.35    ,  18.39    ,
        18.4     ,  18.44    ,  18.46    ,  18.47    ,  18.5     ,
        18.55    ,  18.57    ,  18.6     ,  18.61    ,  18.62    ,
        18.7     ,  18.72    ,  18.79    ,  18.8     ,  18.83    ,
        18.84    ,  18.86    ,  18.88    ,  18.9     ,  18.93    ,
        18.95    ,  19.      ,  19.03    ,  19.1     ,  19.15    ,
        19.2     ,  19.22    ,  19.3     ,  19.35    ,  19.4     ,
        19.5     ,  19.52    ,  19.55    ,  19.6     ,  19.65    ,
        19.7     ,  19.8     ,  19.9     ,  19.95    ,  20.      ,
        20.02    ,  20.03    ,  20.1     ,  20.11    ,  20.13    ,
        20.19    ,  20.2     ,  20.26    ,  20.3     ,  20.31    ,
        20.36    ,  20.39    ,  20.4     ,  20.46    ,  20.5     ,
        20.52    ,  20.55    ,  20.6     ,  20.67    ,  20.7     ,
        20.74    ,  20.75    ,  20.77    ,  20.8     ,  20.9     ,
        20.97    ,  21.      ,  21.04    ,  21.06    ,  21.08    ,
        21.09    ,  21.1     ,  21.11    ,  21.12    ,  21.15    ,
        21.2     ,  21.28    ,  21.3     ,  21.4     ,  21.5     ,
        21.53    ,  21.59    ,  21.6     ,  21.65    ,  21.68    ,
        21.7     ,  21.77    ,  21.8     ,  21.9     ,  22.      ,
        22.04    ,  22.1     ,  22.15    ,  22.2     ,  22.3     ,
        22.35    ,  22.37    ,  22.4     ,  22.43    ,  22.45    ,
        22.5     ,  22.57    ,  22.6     ,  22.62    ,  22.7     ,
        22.8     ,  22.81    ,  22.9     ,  23.      ,  23.1     ,
        23.19    ,  23.2     ,  23.3     ,  23.4     ,  23.43    ,
        23.5     ,  23.6     ,  23.7     ,  23.77    ,  23.8     ,
        23.9     ,  24.      ,  24.1     ,  24.2     ,  24.3     ,
        24.4     ,  24.42    ,  24.5     ,  24.6     ,  24.64    ,
        24.7     ,  24.75    ,  24.77    ,  24.8     ,  24.83    ,
        24.86    ,  24.89    ,  24.9     ,  25.      ,  25.1     ,
        25.2     ,  25.3     ,  25.38    ,  25.4     ,  25.41    ,
        25.44    ,  25.5     ,  25.6     ,  25.7     ,  25.8     ,
        25.81    ,  25.9     ,  25.900002,  25.95    ,  25.97    ,
        26.      ,  26.1     ,  26.13    ,  26.2     ,  26.21    ,
        26.28    ,  26.29    ,  26.3     ,  26.4     ,  26.5     ,
        26.51    ,  26.599998,  26.6     ,  26.61    ,  26.7     ,
        26.75    ,  26.79    ,  26.8     ,  26.87    ,  26.9     ,
        26.94    ,  27.      ,  27.05    ,  27.06    ,  27.1     ,
        27.12    ,  27.2     ,  27.22    ,  27.25    ,  27.29    ,
        27.3     ,  27.33    ,  27.380001,  27.4     ,  27.42    ,
        27.43    ,  27.46    ,  27.5     ,  27.51    ,  27.57    ,
        27.6     ,  27.67    ,  27.69    ,  27.7     ,  27.75    ,
        27.77    ,  27.8     ,  27.88    ,  27.89    ,  27.9     ,
        27.92    ,  27.95    ,  28.      ,  28.01    ,  28.02    ,
        28.07    ,  28.09    ,  28.1     ,  28.14    ,  28.15    ,
        28.18    ,  28.2     ,  28.23    ,  28.26    ,  28.3     ,
        28.300001,  28.31    ,  28.33    ,  28.34    ,  28.36    ,
        28.4     ,  28.42    ,  28.43    ,  28.45    ,  28.47    ,
        28.48    ,  28.5     ,  28.54    ,  28.55    ,  28.6     ,
        28.66    ,  28.7     ,  28.71    ,  28.73    ,  28.77    ,
        28.8     ,  28.81    ,  28.84    ,  28.85    ,  28.86    ,
        28.88    ,  28.9     ,  28.900002,  28.98    ,  29.      ,
        29.01    ,  29.08    ,  29.1     ,  29.13    ,  29.16    ,
        29.2     ,  29.21    ,  29.22    ,  29.27    ,  29.3     ,
        29.34    ,  29.38    ,  29.4     ,  29.41    ,  29.43    ,
        29.48    ,  29.5     ,  29.52    ,  29.55    ,  29.56    ,
        29.599998,  29.6     ,  29.61    ,  29.67    ,  29.7     ,
        29.72    ,  29.74    ,  29.77    ,  29.78    ,  29.8     ,
        29.81    ,  29.83    ,  29.84    ,  29.85    ,  29.9     ,
        29.92    ,  30.      ,  30.01    ,  30.04    ,  30.05    ,
        30.08    ,  30.099998,  30.1     ,  30.12    ,  30.15    ,
        30.16    ,  30.17    ,  30.2     ,  30.29    ,  30.3     ,
        30.31    ,  30.35    ,  30.39    ,  30.4     ,  30.5     ,
        30.52    ,  30.55    ,  30.57    ,  30.59    ,  30.6     ,
        30.61    ,  30.62    ,  30.7     ,  30.72    ,  30.75    ,
        30.8     ,  30.81    ,  30.82    ,  30.83    ,  30.89    ,
        30.9     ,  30.900002,  30.92    ,  31.      ,  31.01    ,
        31.04    ,  31.05    ,  31.07    ,  31.1     ,  31.12    ,
        31.18    ,  31.2     ,  31.26    ,  31.29    ,  31.3     ,
        31.38    ,  31.4     ,  31.41    ,  31.42    ,  31.43    ,
        31.44    ,  31.47    ,  31.48    ,  31.5     ,  31.51    ,
        31.52    ,  31.55    ,  31.599998,  31.6     ,  31.61    ,
        31.62    ,  31.64    ,  31.65    ,  31.7     ,  31.71    ,
        31.74    ,  31.77    ,  31.8     ,  31.81    ,  31.9     ,
        32.      ,  32.02    ,  32.04    ,  32.05    ,  32.06    ,
        32.08    ,  32.1     ,  32.199997,  32.2     ,  32.26    ,
        32.3     ,  32.35    ,  32.37    ,  32.38    ,  32.4     ,
        32.46    ,  32.5     ,  32.6     ,  32.61    ,  32.62    ,
        32.7     ,  32.71    ,  32.73    ,  32.79    ,  32.8     ,
        32.84    ,  32.9     ,  32.95    ,  33.      ,  33.03    ,
        33.06    ,  33.08    ,  33.1     ,  33.18    ,  33.2     ,
        33.26    ,  33.260002,  33.3     ,  33.36    ,  33.4     ,
        33.47    ,  33.5     ,  33.57    ,  33.6     ,  33.63    ,
        33.67    ,  33.7     ,  33.72    ,  33.73    ,  33.8     ,
        33.87    ,  33.9     ,  33.92    ,  34.      ,  34.1     ,
        34.14    ,  34.2     ,  34.29    ,  34.3     ,  34.32    ,
        34.37    ,  34.4     ,  34.41    ,  34.44    ,  34.5     ,
        34.51    ,  34.6     ,  34.63    ,  34.7     ,  34.760002,
        34.79    ,  34.8     ,  34.87    ,  34.88    ,  34.9     ,
        35.      ,  35.01    ,  35.05    ,  35.07    ,  35.1     ,
        35.17    ,  35.2     ,  35.3     ,  35.33    ,  35.38    ,
        35.4     ,  35.48    ,  35.5     ,  35.55    ,  35.6     ,
        35.61    ,  35.7     ,  35.74    ,  35.76    ,  35.77    ,
        35.8     ,  35.81    ,  35.88    ,  35.89    ,  35.9     ,
        35.91    ,  35.92    ,  36.      ,  36.04    ,  36.07    ,
        36.1     ,  36.15    ,  36.2     ,  36.27    ,  36.3     ,
        36.35    ,  36.4     ,  36.45    ,  36.5     ,  36.57    ,
        36.6     ,  36.7     ,  36.76    ,  36.79    ,  36.8     ,
        36.81    ,  36.86    ,  36.9     ,  36.95    ,  37.      ,
        37.1     ,  37.13    ,  37.2     ,  37.28    ,  37.3     ,
        37.300003,  37.4     ,  37.5     ,  37.52    ,  37.6     ,
        37.66    ,  37.7     ,  37.74    ,  37.8     ,  37.9     ,
        38.      ,  38.03    ,  38.05    ,  38.07    ,  38.1     ,
        38.18    ,  38.2     ,  38.3     ,  38.33    ,  38.39    ,
        38.4     ,  38.5     ,  38.6     ,  38.7     ,  38.73    ,
        38.8     ,  38.9     ,  38.91    ,  38.95    ,  38.99    ,
        39.      ,  39.07    ,  39.1     ,  39.18    ,  39.2     ,
        39.3     ,  39.4     ,  39.41    ,  39.5     ,  39.59    ,
        39.6     ,  39.62    ,  39.66    ,  39.7     ,  39.71    ,
        39.78    ,  39.8     ,  39.85    ,  39.9     ,  40.      ,
        40.06    ,  40.1     ,  40.2     ,  40.3     ,  40.32    ,
        40.39    ,  40.4     ,  40.43    ,  40.5     ,  40.57    ,
        40.59    ,  40.6     ,  40.61    ,  40.7     ,  40.79    ,
        40.8     ,  40.83    ,  40.9     ,  40.92    ,  40.95    ,
        41.      ,  41.05    ,  41.06    ,  41.08    ,  41.1     ,
        41.17    ,  41.19    ,  41.2     ,  41.3     ,  41.34    ,
        41.35    ,  41.4     ,  41.44    ,  41.5     ,  41.6     ,
        41.69    ,  41.7     ,  41.8     ,  41.9     ,  41.92    ,
        41.98    ,  42.      ,  42.1     ,  42.17    ,  42.2     ,
        42.26    ,  42.3     ,  42.31    ,  42.4     ,  42.41    ,
        42.43    ,  42.48    ,  42.5     ,  42.54    ,  42.55    ,
        42.6     ,  42.7     ,  42.8     ,  42.9     ,  42.91    ,
        43.      ,  43.05    ,  43.1     ,  43.15    ,  43.2     ,
        43.3     ,  43.32    ,  43.4     ,  43.45    ,  43.46    ,
        43.5     ,  43.6     ,  43.62    ,  43.63    ,  43.7     ,
        43.71    ,  43.78    ,  43.8     ,  43.81    ,  43.83    ,
        43.89    ,  43.9     ,  43.92    ,  44.      ,  44.000004,
        44.04    ,  44.05    ,  44.1     ,  44.100002,  44.13    ,
        44.15    ,  44.2     ,  44.3     ,  44.4     ,  44.5     ,
        44.56    ,  44.6     ,  44.7     ,  44.8     ,  44.9     ,
        44.91    ,  44.99    ,  45.      ,  45.1     ,  45.11    ,
        45.13    ,  45.18    ,  45.2     ,  45.23    ,  45.3     ,
        45.34    ,  45.38    ,  45.4     ,  45.5     ,  45.6     ,
        45.7     ,  45.72    ,  45.8     ,  45.82    ,  45.85    ,
        45.86    ,  45.9     ,  45.92    ,  45.95    ,  46.      ,
        46.01    ,  46.05    ,  46.1     ,  46.13    ,  46.14    ,
        46.15    ,  46.2     ,  46.3     ,  46.4     ,  46.5     ,
        46.57    ,  46.6     ,  46.64    ,  46.7     ,  46.75    ,
        46.8     ,  46.9     ,  47.      ,  47.1     ,  47.11    ,
        47.2     ,  47.24    ,  47.3     ,  47.37    ,  47.4     ,
        47.43    ,  47.5     ,  47.53    ,  47.6     ,  47.68    ,
        47.7     ,  47.8     ,  47.9     ,  47.999996,  48.      ,
        48.05    ,  48.1     ,  48.13    ,  48.2     ,  48.25    ,
        48.3     ,  48.300003,  48.35    ,  48.36    ,  48.38    ,
        48.4     ,  48.41    ,  48.42    ,  48.45    ,  48.46    ,
        48.48    ,  48.49    ,  48.5     ,  48.6     ,  48.62    ,
        48.7     ,  48.8     ,  48.84    ,  48.88    ,  48.9     ,
        48.93    ,  48.94    ,  49.      ,  49.1     ,  49.2     ,
        49.25    ,  49.27    ,  49.28    ,  49.3     ,  49.33    ,
        49.4     ,  49.46    ,  49.5     ,  49.58    ,  49.6     ,
        49.7     ,  49.74    ,  49.8     ,  49.87    ,  49.9     ,
        49.98    ,  50.      ,  50.02    ,  50.08    ,  50.1     ,
        50.16    ,  50.2     ,  50.25    ,  50.26    ,  50.28    ,
        50.3     ,  50.34    ,  50.4     ,  50.47    ,  50.5     ,
        50.6     ,  50.64    ,  50.7     ,  50.8     ,  50.81    ,
        50.9     ,  51.      ,  51.07    ,  51.1     ,  51.2     ,
        51.3     ,  51.4     ,  51.5     ,  51.6     ,  51.7     ,
        51.76    ,  51.78    ,  51.8     ,  51.88    ,  51.9     ,
        52.      ,  52.02    ,  52.1     ,  52.2     ,  52.21    ,
        52.26    ,  52.3     ,  52.4     ,  52.5     ,  52.53    ,
        52.6     ,  52.65    ,  52.7     ,  52.77    ,  52.8     ,
        52.9     ,  52.94    ,  53.      ,  53.1     ,  53.15    ,
        53.17    ,  53.2     ,  53.3     ,  53.31    ,  53.33    ,
        53.35    ,  53.4     ,  53.5     ,  53.6     ,  53.7     ,
        53.8     ,  53.9     ,  54.      ,  54.09    ,  54.1     ,
        54.13    ,  54.2     ,  54.3     ,  54.4     ,  54.43    ,
        54.48    ,  54.5     ,  54.6     ,  54.7     ,  54.74    ,
        54.8     ,  54.9     ,  55.      ,  55.1     ,  55.2     ,
        55.22    ,  55.3     ,  55.35    ,  55.38    ,  55.4     ,
        55.5     ,  55.6     ,  55.7     ,  55.8     ,  55.84    ,
        55.9     ,  56.      ,  56.1     ,  56.12    ,  56.2     ,
        56.3     ,  56.4     ,  56.5     ,  56.53    ,  56.6     ,
        56.7     ,  56.8     ,  56.86    ,  56.9     ,  57.      ,
        57.1     ,  57.2     ,  57.3     ,  57.35    ,  57.4     ,
        57.5     ,  57.51    ,  57.6     ,  57.7     ,  57.75    ,
        57.8     ,  57.9     ,  58.      ,  58.1     ,  58.18    ,
        58.2     ,  58.3     ,  58.4     ,  58.44    ,  58.5     ,
        58.6     ,  58.63    ,  58.7     ,  58.8     ,  58.82    ,
        59.      ,  59.1     ,  59.12    ,  59.2     ,  59.3     ,
        59.4     ,  59.5     ,  59.6     ,  59.7     ,  59.8     ,
        59.9     ,  60.      ,  60.1     ,  60.2     ,  60.3     ,
        60.300003,  60.33    ,  60.4     ,  60.5     ,  60.6     ,
        60.7     ,  60.77    ,  60.8     ,  60.9     ,  61.      ,
        61.1     ,  61.2     ,  61.3     ,  61.35    ,  61.4     ,
        61.5     ,  61.6     ,  61.7     ,  61.8     ,  61.9     ,
        62.      ,  62.1     ,  62.2     ,  62.3     ,  62.4     ,
        62.5     ,  62.6     ,  62.7     ,  62.75    ,  62.8     ,
        62.9     ,  63.      ,  63.1     ,  63.2     ,  63.3     ,
        63.31    ,  63.4     ,  63.5     ,  63.6     ,  63.7     ,
        63.72    ,  63.8     ,  63.9     ,  64.      ,  64.1     ,
        64.2     ,  64.3     ,  64.32    ,  64.4     ,  64.5     ,
        64.6     ,  64.7     ,  64.8     ,  64.9     ,  65.      ,
        65.3     ,  65.4     ,  65.5     ,  65.6     ,  65.7     ,
        65.72    ,  65.8     ,  65.9     ,  65.93    ,  66.      ,
        66.01    ,  66.1     ,  66.2     ,  66.22    ,  66.24    ,
        66.3     ,  66.4     ,  66.5     ,  66.6     ,  66.7     ,
        66.8     ,  66.9     ,  66.99    ,  67.      ,  67.01    ,
        67.1     ,  67.2     ,  67.3     ,  67.4     ,  67.5     ,
        67.6     ,  67.8     ,  67.81    ,  67.9     ,  68.      ,
        68.1     ,  68.3     ,  68.4     ,  68.48    ,  68.5     ,
        68.6     ,  68.7     ,  68.8     ,  68.9     ,  69.      ,
        69.1     ,  69.2     ,  69.28    ,  69.3     ,  69.5     ,
        69.6     ,  69.7     ,  69.75    ,  69.8     ,  69.9     ,
        70.      ,  70.1     ,  70.3     ,  70.4     ,  70.48    ,
        70.5     ,  70.6     ,  70.7     ,  70.9     ,  71.      ,
        71.1     ,  71.2     ,  71.3     ,  71.4     ,  71.5     ,
        71.7     ,  71.72    ,  71.9     ,  72.      ,  72.1     ,
        72.2     ,  72.3     ,  72.4     ,  72.5     ,  72.52    ,
        72.6     ,  72.7     ,  72.79    ,  72.8     ,  73.      ,
        73.1     ,  73.2     ,  73.3     ,  73.4     ,  73.5     ,
        73.6     ,  73.8     ,  73.9     ,  74.      ,  74.1     ,
        74.16    ,  74.2     ,  74.3     ,  74.4     ,  74.6     ,
        74.8     ,  74.99    ,  75.      ,  75.1     ,  75.2     ,
        75.25    ,  75.4     ,  75.5     ,  75.6     ,  75.7     ,
        75.8     ,  75.83    ,  76.      ,  76.1     ,  76.2     ,
        76.3     ,  76.4     ,  76.5     ,  76.65    ,  76.7     ,
        76.8     ,  76.9     ,  77.      ,  77.1     ,  77.2     ,
        77.3     ,  77.35    ,  77.4     ,  77.5     ,  77.6     ,
        77.61    ,  77.71    ,  77.8     ,  78.      ,  78.03    ,
        78.4     ,  78.5     ,  78.6     ,  78.9     ,  79.      ,
        79.2     ,  79.28    ,  79.3     ,  79.34    ,  79.4     ,
        79.42    ,  79.5     ,  79.7     ,  79.74    ,  80.      ,
        80.1     ,  80.2     ,  80.3     ,  80.39    ,  80.5     ,
        80.62    ,  80.7     ,  80.8     ,  80.9     ,  81.      ,
        81.1     ,  81.3     ,  81.4     ,  81.5     ,  81.6     ,
        81.66    ,  81.7     ,  81.899994,  81.9     ,  82.      ,
        82.05    ,  82.1     ,  82.2     ,  82.3     ,  82.4     ,
        82.55    ,  82.8     ,  82.9     ,  83.      ,  83.2     ,
        83.5     ,  83.6     ,  83.7     ,  83.8     ,  84.      ,
        84.1     ,  84.2     ,  84.5     ,  84.6     ,  84.69    ,
        84.7     ,  85.      ,  85.1     ,  85.2     ,  85.3     ,
        85.6     ,  86.      ,  86.1     ,  86.2     ,  86.6     ,
        86.7     ,  87.      ,  87.2     ,  87.23    ,  87.5     ,
        87.7     ,  87.8     ,  88.      ,  88.1     ,  88.2     ,
        88.3     ,  89.      ,  89.100006,  89.11    ,  89.2     ,
        89.3     ,  89.4     ,  89.5     ,  89.6     ,  89.7     ,
        89.9     ,  90.      ,  90.2     ,  90.6     ,  90.7     ,
        91.      ,  91.2     ,  91.24    ,  91.7     ,  91.77    ,
        91.8     ,  92.      ,  92.1     ,  92.3     ,  92.34    ,
        92.5     ,  92.6     ,  92.7     ,  92.8     ,  92.9     ,
        93.      ,  93.1     ,  93.2     ,  93.5     ,  93.6     ,
        94.      ,  94.1     ,  94.4     ,  94.54    ,  94.8     ,
        94.89    ,  94.9     ,  95.      ,  95.1     ,  95.2     ,
        95.4     ,  95.41    ,  95.45    ,  95.6     ,  95.7     ,
        95.9     ,  96.      ,  96.3     ,  96.4     ,  96.6     ,
        96.7     ,  97.      ,  97.2     ,  97.3     ,  97.6     ,
        98.      ,  98.2     ,  98.5     ,  98.7     ,  98.9     ,
        99.      ,  99.1     ,  99.21    ,  99.3     ,  99.5     ,
        99.6     ,  99.7     ,  99.8     ,  99.9     , 100.      ,
       100.1     , 100.23    , 100.4     , 100.7     , 100.9     ,
       101.      , 101.2     , 101.54    , 101.82    , 102.      ,
       102.2     , 102.3     , 102.5     , 102.8     , 103.      ,
       103.1     , 103.3     , 103.6     , 103.7     , 103.8     ,
       104.      , 104.1     , 104.2     , 104.76    , 104.8     ,
       105.      , 105.3     , 105.8     , 106.      , 106.1     ,
       106.2     , 106.4     , 106.5     , 107.      , 107.03    ,
       107.6     , 108.      , 108.8     , 109.      , 109.4     ,
       109.51    , 110.      , 110.3     , 110.4     , 110.8     ,
       111.      , 111.1     , 111.6     , 111.86    , 112.      ,
       112.2     , 112.4     , 112.7     , 113.      , 114.      ,
       114.7     , 114.8     , 115.      , 115.5     , 115.8     ,
       116.      , 116.2     , 117.      , 117.1     , 117.3     ,
       117.4     , 118.4     , 118.5     , 118.9     , 119.      ,
       119.3     , 119.5     , 119.9     , 120.      , 121.      ,
       121.6     , 122.      , 122.1     , 123.      , 123.1     ,
       123.27    , 123.6     , 123.9     , 124.      , 124.9     ,
       125.      , 125.1     , 125.5     , 125.7     , 125.9     ,
       126.      , 126.4     , 126.6     , 127.      , 127.7     ,
       128.      , 129.      , 130.      , 130.3     , 131.      ,
       131.5     , 132.      , 133.      , 133.4     , 134.      ,
       134.7     , 134.8     , 136.      , 136.1     , 136.2     ,
       137.7     , 138.8     , 139.      , 139.4     , 139.8     ,
       140.      , 141.      , 142.      , 143.      , 144.5     ,
       144.6     , 145.      , 145.4     , 145.5     , 145.9     ,
       147.      , 147.2     , 148.      , 148.6     , 149.4     ,
       150.      , 150.4     , 150.8     , 151.      , 151.1     ,
       151.4     , 151.6     , 152.      , 153.      , 153.9     ,
       154.      , 154.7     , 155.      , 155.1     , 155.5     ,
       157.      , 159.2     , 159.5     , 159.6     , 159.9     ,
       160.      , 160.1     , 160.6     , 161.4     , 162.      ,
       163.2     , 163.5     , 164.3     , 164.7     , 165.      ,
       165.5     , 166.7     , 167.      , 168.3     , 170.      ,
       170.8     , 171.      , 174.      , 174.3     , 175.      ,
       176.2     , 176.6     , 177.      , 177.3     , 179.      ,
       179.2     , 180.      , 181.8     , 182.      , 182.8     ,
       183.      , 183.7     , 184.      , 184.9     , 187.      ,
       187.9     , 188.7     , 189.4     , 190.      , 193.      ,
       193.5     , 194.      , 195.      , 198.      , 199.      ,
       200.      , 204.      , 211.      , 216.      , 218.      ,
       220.      , 222.      , 225.9     , 230.      , 239.4     ,
       248.5     , 248.7     , 250.      , 255.7     , 258.      ,
       260.      , 264.5     , 274.      , 279.6     , 300.      ,
       301.5     , 312.5     , 322.3     , 332.      , 347.5     ,
       409.      , 409.7     ,        nan])
In [47]:
data['living_area'] = data[data['living_area'].notna()]['living_area'].round(2)
data['living_area'].sort_values().unique()
Out[47]:
array([  2.  ,   3.  ,   5.  ,   5.4 ,   6.  ,   6.5 ,   8.  ,   8.3 ,
         8.4 ,   8.5 ,   8.9 ,   9.  ,   9.1 ,   9.8 ,  10.  ,  10.08,
        10.3 ,  10.4 ,  10.5 ,  10.52,  10.55,  10.6 ,  10.7 ,  10.76,
        10.8 ,  10.9 ,  10.93,  10.94,  11.  ,  11.1 ,  11.15,  11.2 ,
        11.3 ,  11.38,  11.4 ,  11.47,  11.5 ,  11.6 ,  11.7 ,  11.79,
        11.88,  11.9 ,  11.99,  12.  ,  12.08,  12.1 ,  12.18,  12.2 ,
        12.28,  12.3 ,  12.5 ,  12.6 ,  12.7 ,  12.71,  12.79,  12.8 ,
        12.81,  12.9 ,  13.  ,  13.05,  13.09,  13.1 ,  13.15,  13.2 ,
        13.27,  13.3 ,  13.32,  13.34,  13.37,  13.4 ,  13.46,  13.5 ,
        13.54,  13.56,  13.59,  13.6 ,  13.62,  13.66,  13.7 ,  13.73,
        13.76,  13.79,  13.8 ,  13.82,  13.89,  13.9 ,  13.92,  14.  ,
        14.01,  14.02,  14.03,  14.06,  14.08,  14.1 ,  14.11,  14.16,
        14.17,  14.19,  14.2 ,  14.22,  14.23,  14.25,  14.28,  14.3 ,
        14.31,  14.35,  14.37,  14.38,  14.39,  14.4 ,  14.41,  14.45,
        14.46,  14.47,  14.5 ,  14.51,  14.55,  14.56,  14.57,  14.58,
        14.59,  14.6 ,  14.62,  14.64,  14.65,  14.69,  14.7 ,  14.71,
        14.73,  14.74,  14.77,  14.8 ,  14.85,  14.89,  14.9 ,  14.91,
        14.92,  14.95,  15.  ,  15.01,  15.02,  15.03,  15.04,  15.05,
        15.06,  15.07,  15.08,  15.1 ,  15.11,  15.12,  15.13,  15.15,
        15.16,  15.18,  15.2 ,  15.25,  15.26,  15.3 ,  15.31,  15.32,
        15.33,  15.34,  15.35,  15.36,  15.37,  15.38,  15.4 ,  15.41,
        15.42,  15.43,  15.45,  15.46,  15.5 ,  15.53,  15.54,  15.55,
        15.58,  15.6 ,  15.61,  15.62,  15.64,  15.65,  15.66,  15.7 ,
        15.71,  15.72,  15.77,  15.78,  15.79,  15.8 ,  15.82,  15.85,
        15.86,  15.88,  15.89,  15.9 ,  15.91,  15.92,  15.93,  15.96,
        16.  ,  16.04,  16.06,  16.07,  16.08,  16.09,  16.1 ,  16.11,
        16.12,  16.15,  16.16,  16.18,  16.2 ,  16.22,  16.26,  16.29,
        16.3 ,  16.31,  16.32,  16.4 ,  16.41,  16.42,  16.47,  16.5 ,
        16.51,  16.52,  16.55,  16.58,  16.59,  16.6 ,  16.61,  16.62,
        16.63,  16.66,  16.68,  16.69,  16.7 ,  16.71,  16.72,  16.74,
        16.76,  16.8 ,  16.83,  16.84,  16.88,  16.9 ,  16.91,  16.92,
        16.93,  16.94,  16.95,  16.96,  16.97,  16.98,  17.  ,  17.01,
        17.03,  17.04,  17.05,  17.07,  17.08,  17.1 ,  17.11,  17.12,
        17.14,  17.19,  17.2 ,  17.22,  17.25,  17.26,  17.27,  17.3 ,
        17.33,  17.34,  17.35,  17.36,  17.38,  17.4 ,  17.43,  17.45,
        17.48,  17.49,  17.5 ,  17.51,  17.53,  17.6 ,  17.62,  17.65,
        17.66,  17.7 ,  17.71,  17.73,  17.78,  17.8 ,  17.82,  17.83,
        17.84,  17.85,  17.87,  17.9 ,  17.92,  17.93,  17.95,  17.97,
        18.  ,  18.02,  18.03,  18.04,  18.08,  18.09,  18.1 ,  18.11,
        18.12,  18.14,  18.15,  18.16,  18.19,  18.2 ,  18.23,  18.28,
        18.3 ,  18.33,  18.34,  18.35,  18.39,  18.4 ,  18.44,  18.46,
        18.47,  18.5 ,  18.55,  18.57,  18.6 ,  18.61,  18.62,  18.7 ,
        18.72,  18.79,  18.8 ,  18.83,  18.84,  18.86,  18.88,  18.9 ,
        18.93,  18.95,  19.  ,  19.03,  19.1 ,  19.15,  19.2 ,  19.22,
        19.3 ,  19.35,  19.4 ,  19.5 ,  19.52,  19.55,  19.6 ,  19.65,
        19.7 ,  19.8 ,  19.9 ,  19.95,  20.  ,  20.02,  20.03,  20.1 ,
        20.11,  20.13,  20.19,  20.2 ,  20.26,  20.3 ,  20.31,  20.36,
        20.39,  20.4 ,  20.46,  20.5 ,  20.52,  20.55,  20.6 ,  20.67,
        20.7 ,  20.74,  20.75,  20.77,  20.8 ,  20.9 ,  20.97,  21.  ,
        21.04,  21.06,  21.08,  21.09,  21.1 ,  21.11,  21.12,  21.15,
        21.2 ,  21.28,  21.3 ,  21.4 ,  21.5 ,  21.53,  21.59,  21.6 ,
        21.65,  21.68,  21.7 ,  21.77,  21.8 ,  21.9 ,  22.  ,  22.04,
        22.1 ,  22.15,  22.2 ,  22.3 ,  22.35,  22.37,  22.4 ,  22.43,
        22.45,  22.5 ,  22.57,  22.6 ,  22.62,  22.7 ,  22.8 ,  22.81,
        22.9 ,  23.  ,  23.1 ,  23.19,  23.2 ,  23.3 ,  23.4 ,  23.43,
        23.5 ,  23.6 ,  23.7 ,  23.77,  23.8 ,  23.9 ,  24.  ,  24.1 ,
        24.2 ,  24.3 ,  24.4 ,  24.42,  24.5 ,  24.6 ,  24.64,  24.7 ,
        24.75,  24.77,  24.8 ,  24.83,  24.86,  24.89,  24.9 ,  25.  ,
        25.1 ,  25.2 ,  25.3 ,  25.38,  25.4 ,  25.41,  25.44,  25.5 ,
        25.6 ,  25.7 ,  25.8 ,  25.81,  25.9 ,  25.95,  25.97,  26.  ,
        26.1 ,  26.13,  26.2 ,  26.21,  26.28,  26.29,  26.3 ,  26.4 ,
        26.5 ,  26.51,  26.6 ,  26.61,  26.7 ,  26.75,  26.79,  26.8 ,
        26.87,  26.9 ,  26.94,  27.  ,  27.05,  27.06,  27.1 ,  27.12,
        27.2 ,  27.22,  27.25,  27.29,  27.3 ,  27.33,  27.38,  27.4 ,
        27.42,  27.43,  27.46,  27.5 ,  27.51,  27.57,  27.6 ,  27.67,
        27.69,  27.7 ,  27.75,  27.77,  27.8 ,  27.88,  27.89,  27.9 ,
        27.92,  27.95,  28.  ,  28.01,  28.02,  28.07,  28.09,  28.1 ,
        28.14,  28.15,  28.18,  28.2 ,  28.23,  28.26,  28.3 ,  28.31,
        28.33,  28.34,  28.36,  28.4 ,  28.42,  28.43,  28.45,  28.47,
        28.48,  28.5 ,  28.54,  28.55,  28.6 ,  28.66,  28.7 ,  28.71,
        28.73,  28.77,  28.8 ,  28.81,  28.84,  28.85,  28.86,  28.88,
        28.9 ,  28.98,  29.  ,  29.01,  29.08,  29.1 ,  29.13,  29.16,
        29.2 ,  29.21,  29.22,  29.27,  29.3 ,  29.34,  29.38,  29.4 ,
        29.41,  29.43,  29.48,  29.5 ,  29.52,  29.55,  29.56,  29.6 ,
        29.61,  29.67,  29.7 ,  29.72,  29.74,  29.77,  29.78,  29.8 ,
        29.81,  29.83,  29.84,  29.85,  29.9 ,  29.92,  30.  ,  30.01,
        30.04,  30.05,  30.08,  30.1 ,  30.12,  30.15,  30.16,  30.17,
        30.2 ,  30.29,  30.3 ,  30.31,  30.35,  30.39,  30.4 ,  30.5 ,
        30.52,  30.55,  30.57,  30.59,  30.6 ,  30.61,  30.62,  30.7 ,
        30.72,  30.75,  30.8 ,  30.81,  30.82,  30.83,  30.89,  30.9 ,
        30.92,  31.  ,  31.01,  31.04,  31.05,  31.07,  31.1 ,  31.12,
        31.18,  31.2 ,  31.26,  31.29,  31.3 ,  31.38,  31.4 ,  31.41,
        31.42,  31.43,  31.44,  31.47,  31.48,  31.5 ,  31.51,  31.52,
        31.55,  31.6 ,  31.61,  31.62,  31.64,  31.65,  31.7 ,  31.71,
        31.74,  31.77,  31.8 ,  31.81,  31.9 ,  32.  ,  32.02,  32.04,
        32.05,  32.06,  32.08,  32.1 ,  32.2 ,  32.26,  32.3 ,  32.35,
        32.37,  32.38,  32.4 ,  32.46,  32.5 ,  32.6 ,  32.61,  32.62,
        32.7 ,  32.71,  32.73,  32.79,  32.8 ,  32.84,  32.9 ,  32.95,
        33.  ,  33.03,  33.06,  33.08,  33.1 ,  33.18,  33.2 ,  33.26,
        33.3 ,  33.36,  33.4 ,  33.47,  33.5 ,  33.57,  33.6 ,  33.63,
        33.67,  33.7 ,  33.72,  33.73,  33.8 ,  33.87,  33.9 ,  33.92,
        34.  ,  34.1 ,  34.14,  34.2 ,  34.29,  34.3 ,  34.32,  34.37,
        34.4 ,  34.41,  34.44,  34.5 ,  34.51,  34.6 ,  34.63,  34.7 ,
        34.76,  34.79,  34.8 ,  34.87,  34.88,  34.9 ,  35.  ,  35.01,
        35.05,  35.07,  35.1 ,  35.17,  35.2 ,  35.3 ,  35.33,  35.38,
        35.4 ,  35.48,  35.5 ,  35.55,  35.6 ,  35.61,  35.7 ,  35.74,
        35.76,  35.77,  35.8 ,  35.81,  35.88,  35.89,  35.9 ,  35.91,
        35.92,  36.  ,  36.04,  36.07,  36.1 ,  36.15,  36.2 ,  36.27,
        36.3 ,  36.35,  36.4 ,  36.45,  36.5 ,  36.57,  36.6 ,  36.7 ,
        36.76,  36.79,  36.8 ,  36.81,  36.86,  36.9 ,  36.95,  37.  ,
        37.1 ,  37.13,  37.2 ,  37.28,  37.3 ,  37.4 ,  37.5 ,  37.52,
        37.6 ,  37.66,  37.7 ,  37.74,  37.8 ,  37.9 ,  38.  ,  38.03,
        38.05,  38.07,  38.1 ,  38.18,  38.2 ,  38.3 ,  38.33,  38.39,
        38.4 ,  38.5 ,  38.6 ,  38.7 ,  38.73,  38.8 ,  38.9 ,  38.91,
        38.95,  38.99,  39.  ,  39.07,  39.1 ,  39.18,  39.2 ,  39.3 ,
        39.4 ,  39.41,  39.5 ,  39.59,  39.6 ,  39.62,  39.66,  39.7 ,
        39.71,  39.78,  39.8 ,  39.85,  39.9 ,  40.  ,  40.06,  40.1 ,
        40.2 ,  40.3 ,  40.32,  40.39,  40.4 ,  40.43,  40.5 ,  40.57,
        40.59,  40.6 ,  40.61,  40.7 ,  40.79,  40.8 ,  40.83,  40.9 ,
        40.92,  40.95,  41.  ,  41.05,  41.06,  41.08,  41.1 ,  41.17,
        41.19,  41.2 ,  41.3 ,  41.34,  41.35,  41.4 ,  41.44,  41.5 ,
        41.6 ,  41.69,  41.7 ,  41.8 ,  41.9 ,  41.92,  41.98,  42.  ,
        42.1 ,  42.17,  42.2 ,  42.26,  42.3 ,  42.31,  42.4 ,  42.41,
        42.43,  42.48,  42.5 ,  42.54,  42.55,  42.6 ,  42.7 ,  42.8 ,
        42.9 ,  42.91,  43.  ,  43.05,  43.1 ,  43.15,  43.2 ,  43.3 ,
        43.32,  43.4 ,  43.45,  43.46,  43.5 ,  43.6 ,  43.62,  43.63,
        43.7 ,  43.71,  43.78,  43.8 ,  43.81,  43.83,  43.89,  43.9 ,
        43.92,  44.  ,  44.04,  44.05,  44.1 ,  44.13,  44.15,  44.2 ,
        44.3 ,  44.4 ,  44.5 ,  44.56,  44.6 ,  44.7 ,  44.8 ,  44.9 ,
        44.91,  44.99,  45.  ,  45.1 ,  45.11,  45.13,  45.18,  45.2 ,
        45.23,  45.3 ,  45.34,  45.38,  45.4 ,  45.5 ,  45.6 ,  45.7 ,
        45.72,  45.8 ,  45.82,  45.85,  45.86,  45.9 ,  45.92,  45.95,
        46.  ,  46.01,  46.05,  46.1 ,  46.13,  46.14,  46.15,  46.2 ,
        46.3 ,  46.4 ,  46.5 ,  46.57,  46.6 ,  46.64,  46.7 ,  46.75,
        46.8 ,  46.9 ,  47.  ,  47.1 ,  47.11,  47.2 ,  47.24,  47.3 ,
        47.37,  47.4 ,  47.43,  47.5 ,  47.53,  47.6 ,  47.68,  47.7 ,
        47.8 ,  47.9 ,  48.  ,  48.05,  48.1 ,  48.13,  48.2 ,  48.25,
        48.3 ,  48.35,  48.36,  48.38,  48.4 ,  48.41,  48.42,  48.45,
        48.46,  48.48,  48.49,  48.5 ,  48.6 ,  48.62,  48.7 ,  48.8 ,
        48.84,  48.88,  48.9 ,  48.93,  48.94,  49.  ,  49.1 ,  49.2 ,
        49.25,  49.27,  49.28,  49.3 ,  49.33,  49.4 ,  49.46,  49.5 ,
        49.58,  49.6 ,  49.7 ,  49.74,  49.8 ,  49.87,  49.9 ,  49.98,
        50.  ,  50.02,  50.08,  50.1 ,  50.16,  50.2 ,  50.25,  50.26,
        50.28,  50.3 ,  50.34,  50.4 ,  50.47,  50.5 ,  50.6 ,  50.64,
        50.7 ,  50.8 ,  50.81,  50.9 ,  51.  ,  51.07,  51.1 ,  51.2 ,
        51.3 ,  51.4 ,  51.5 ,  51.6 ,  51.7 ,  51.76,  51.78,  51.8 ,
        51.88,  51.9 ,  52.  ,  52.02,  52.1 ,  52.2 ,  52.21,  52.26,
        52.3 ,  52.4 ,  52.5 ,  52.53,  52.6 ,  52.65,  52.7 ,  52.77,
        52.8 ,  52.9 ,  52.94,  53.  ,  53.1 ,  53.15,  53.17,  53.2 ,
        53.3 ,  53.31,  53.33,  53.35,  53.4 ,  53.5 ,  53.6 ,  53.7 ,
        53.8 ,  53.9 ,  54.  ,  54.09,  54.1 ,  54.13,  54.2 ,  54.3 ,
        54.4 ,  54.43,  54.48,  54.5 ,  54.6 ,  54.7 ,  54.74,  54.8 ,
        54.9 ,  55.  ,  55.1 ,  55.2 ,  55.22,  55.3 ,  55.35,  55.38,
        55.4 ,  55.5 ,  55.6 ,  55.7 ,  55.8 ,  55.84,  55.9 ,  56.  ,
        56.1 ,  56.12,  56.2 ,  56.3 ,  56.4 ,  56.5 ,  56.53,  56.6 ,
        56.7 ,  56.8 ,  56.86,  56.9 ,  57.  ,  57.1 ,  57.2 ,  57.3 ,
        57.35,  57.4 ,  57.5 ,  57.51,  57.6 ,  57.7 ,  57.75,  57.8 ,
        57.9 ,  58.  ,  58.1 ,  58.18,  58.2 ,  58.3 ,  58.4 ,  58.44,
        58.5 ,  58.6 ,  58.63,  58.7 ,  58.8 ,  58.82,  59.  ,  59.1 ,
        59.12,  59.2 ,  59.3 ,  59.4 ,  59.5 ,  59.6 ,  59.7 ,  59.8 ,
        59.9 ,  60.  ,  60.1 ,  60.2 ,  60.3 ,  60.33,  60.4 ,  60.5 ,
        60.6 ,  60.7 ,  60.77,  60.8 ,  60.9 ,  61.  ,  61.1 ,  61.2 ,
        61.3 ,  61.35,  61.4 ,  61.5 ,  61.6 ,  61.7 ,  61.8 ,  61.9 ,
        62.  ,  62.1 ,  62.2 ,  62.3 ,  62.4 ,  62.5 ,  62.6 ,  62.7 ,
        62.75,  62.8 ,  62.9 ,  63.  ,  63.1 ,  63.2 ,  63.3 ,  63.31,
        63.4 ,  63.5 ,  63.6 ,  63.7 ,  63.72,  63.8 ,  63.9 ,  64.  ,
        64.1 ,  64.2 ,  64.3 ,  64.32,  64.4 ,  64.5 ,  64.6 ,  64.7 ,
        64.8 ,  64.9 ,  65.  ,  65.3 ,  65.4 ,  65.5 ,  65.6 ,  65.7 ,
        65.72,  65.8 ,  65.9 ,  65.93,  66.  ,  66.01,  66.1 ,  66.2 ,
        66.22,  66.24,  66.3 ,  66.4 ,  66.5 ,  66.6 ,  66.7 ,  66.8 ,
        66.9 ,  66.99,  67.  ,  67.01,  67.1 ,  67.2 ,  67.3 ,  67.4 ,
        67.5 ,  67.6 ,  67.8 ,  67.81,  67.9 ,  68.  ,  68.1 ,  68.3 ,
        68.4 ,  68.48,  68.5 ,  68.6 ,  68.7 ,  68.8 ,  68.9 ,  69.  ,
        69.1 ,  69.2 ,  69.28,  69.3 ,  69.5 ,  69.6 ,  69.7 ,  69.75,
        69.8 ,  69.9 ,  70.  ,  70.1 ,  70.3 ,  70.4 ,  70.48,  70.5 ,
        70.6 ,  70.7 ,  70.9 ,  71.  ,  71.1 ,  71.2 ,  71.3 ,  71.4 ,
        71.5 ,  71.7 ,  71.72,  71.9 ,  72.  ,  72.1 ,  72.2 ,  72.3 ,
        72.4 ,  72.5 ,  72.52,  72.6 ,  72.7 ,  72.79,  72.8 ,  73.  ,
        73.1 ,  73.2 ,  73.3 ,  73.4 ,  73.5 ,  73.6 ,  73.8 ,  73.9 ,
        74.  ,  74.1 ,  74.16,  74.2 ,  74.3 ,  74.4 ,  74.6 ,  74.8 ,
        74.99,  75.  ,  75.1 ,  75.2 ,  75.25,  75.4 ,  75.5 ,  75.6 ,
        75.7 ,  75.8 ,  75.83,  76.  ,  76.1 ,  76.2 ,  76.3 ,  76.4 ,
        76.5 ,  76.65,  76.7 ,  76.8 ,  76.9 ,  77.  ,  77.1 ,  77.2 ,
        77.3 ,  77.35,  77.4 ,  77.5 ,  77.6 ,  77.61,  77.71,  77.8 ,
        78.  ,  78.03,  78.4 ,  78.5 ,  78.6 ,  78.9 ,  79.  ,  79.2 ,
        79.28,  79.3 ,  79.34,  79.4 ,  79.42,  79.5 ,  79.7 ,  79.74,
        80.  ,  80.1 ,  80.2 ,  80.3 ,  80.39,  80.5 ,  80.62,  80.7 ,
        80.8 ,  80.9 ,  81.  ,  81.1 ,  81.3 ,  81.4 ,  81.5 ,  81.6 ,
        81.66,  81.7 ,  81.9 ,  82.  ,  82.05,  82.1 ,  82.2 ,  82.3 ,
        82.4 ,  82.55,  82.8 ,  82.9 ,  83.  ,  83.2 ,  83.5 ,  83.6 ,
        83.7 ,  83.8 ,  84.  ,  84.1 ,  84.2 ,  84.5 ,  84.6 ,  84.69,
        84.7 ,  85.  ,  85.1 ,  85.2 ,  85.3 ,  85.6 ,  86.  ,  86.1 ,
        86.2 ,  86.6 ,  86.7 ,  87.  ,  87.2 ,  87.23,  87.5 ,  87.7 ,
        87.8 ,  88.  ,  88.1 ,  88.2 ,  88.3 ,  89.  ,  89.1 ,  89.11,
        89.2 ,  89.3 ,  89.4 ,  89.5 ,  89.6 ,  89.7 ,  89.9 ,  90.  ,
        90.2 ,  90.6 ,  90.7 ,  91.  ,  91.2 ,  91.24,  91.7 ,  91.77,
        91.8 ,  92.  ,  92.1 ,  92.3 ,  92.34,  92.5 ,  92.6 ,  92.7 ,
        92.8 ,  92.9 ,  93.  ,  93.1 ,  93.2 ,  93.5 ,  93.6 ,  94.  ,
        94.1 ,  94.4 ,  94.54,  94.8 ,  94.89,  94.9 ,  95.  ,  95.1 ,
        95.2 ,  95.4 ,  95.41,  95.45,  95.6 ,  95.7 ,  95.9 ,  96.  ,
        96.3 ,  96.4 ,  96.6 ,  96.7 ,  97.  ,  97.2 ,  97.3 ,  97.6 ,
        98.  ,  98.2 ,  98.5 ,  98.7 ,  98.9 ,  99.  ,  99.1 ,  99.21,
        99.3 ,  99.5 ,  99.6 ,  99.7 ,  99.8 ,  99.9 , 100.  , 100.1 ,
       100.23, 100.4 , 100.7 , 100.9 , 101.  , 101.2 , 101.54, 101.82,
       102.  , 102.2 , 102.3 , 102.5 , 102.8 , 103.  , 103.1 , 103.3 ,
       103.6 , 103.7 , 103.8 , 104.  , 104.1 , 104.2 , 104.76, 104.8 ,
       105.  , 105.3 , 105.8 , 106.  , 106.1 , 106.2 , 106.4 , 106.5 ,
       107.  , 107.03, 107.6 , 108.  , 108.8 , 109.  , 109.4 , 109.51,
       110.  , 110.3 , 110.4 , 110.8 , 111.  , 111.1 , 111.6 , 111.86,
       112.  , 112.2 , 112.4 , 112.7 , 113.  , 114.  , 114.7 , 114.8 ,
       115.  , 115.5 , 115.8 , 116.  , 116.2 , 117.  , 117.1 , 117.3 ,
       117.4 , 118.4 , 118.5 , 118.9 , 119.  , 119.3 , 119.5 , 119.9 ,
       120.  , 121.  , 121.6 , 122.  , 122.1 , 123.  , 123.1 , 123.27,
       123.6 , 123.9 , 124.  , 124.9 , 125.  , 125.1 , 125.5 , 125.7 ,
       125.9 , 126.  , 126.4 , 126.6 , 127.  , 127.7 , 128.  , 129.  ,
       130.  , 130.3 , 131.  , 131.5 , 132.  , 133.  , 133.4 , 134.  ,
       134.7 , 134.8 , 136.  , 136.1 , 136.2 , 137.7 , 138.8 , 139.  ,
       139.4 , 139.8 , 140.  , 141.  , 142.  , 143.  , 144.5 , 144.6 ,
       145.  , 145.4 , 145.5 , 145.9 , 147.  , 147.2 , 148.  , 148.6 ,
       149.4 , 150.  , 150.4 , 150.8 , 151.  , 151.1 , 151.4 , 151.6 ,
       152.  , 153.  , 153.9 , 154.  , 154.7 , 155.  , 155.1 , 155.5 ,
       157.  , 159.2 , 159.5 , 159.6 , 159.9 , 160.  , 160.1 , 160.6 ,
       161.4 , 162.  , 163.2 , 163.5 , 164.3 , 164.7 , 165.  , 165.5 ,
       166.7 , 167.  , 168.3 , 170.  , 170.8 , 171.  , 174.  , 174.3 ,
       175.  , 176.2 , 176.6 , 177.  , 177.3 , 179.  , 179.2 , 180.  ,
       181.8 , 182.  , 182.8 , 183.  , 183.7 , 184.  , 184.9 , 187.  ,
       187.9 , 188.7 , 189.4 , 190.  , 193.  , 193.5 , 194.  , 195.  ,
       198.  , 199.  , 200.  , 204.  , 211.  , 216.  , 218.  , 220.  ,
       222.  , 225.9 , 230.  , 239.4 , 248.5 , 248.7 , 250.  , 255.7 ,
       258.  , 260.  , 264.5 , 274.  , 279.6 , 300.  , 301.5 , 312.5 ,
       322.3 , 332.  , 347.5 , 409.  , 409.7 ,    nan])

Теперь значения жилой площади соответствуют установленной точности определения.

Обзор значений

Среди значений жилой площади можно заметить подозрительно маленькие величины — менее 6 м². Рассмотрим записи, в которых жилая площадь объекта недвижимости составляет менее 9 м².

In [48]:
columns = ['total_area', 'living_area', 'kitchen_area', 'studio', 'rooms',
           'floors_total', 'locality_name', 'city_centers_nearest',
           'airports_nearest']

data[columns][data['living_area'] < 9].sort_values(by='living_area')
Out[48]:
total_area living_area kitchen_area studio rooms floors_total locality_name city_centers_nearest airports_nearest
13915 52.0 2.0 9.0 False 2 6.0 Санкт-Петербург 6521.0 32453.0
21758 23.0 2.0 NaN True 0 24.0 Мурино NaN NaN
3242 41.0 3.0 11.0 False 1 17.0 Санкт-Петербург 13073.0 19272.0
23574 139.0 3.0 16.0 False 3 8.0 Санкт-Петербург 5975.0 33255.0
17582 22.0 5.0 NaN True 0 25.0 Санкт-Петербург 11618.0 22735.0
21943 77.6 5.4 9.8 False 4 9.0 Санкт-Петербург 11270.0 29338.0
16431 31.0 6.0 17.0 False 1 5.0 Санкт-Петербург 4826.0 32177.0
19251 33.0 6.5 18.0 False 1 22.0 Санкт-Петербург 10592.0 9258.0
20994 50.6 8.0 31.0 False 2 7.0 Санкт-Петербург 8301.0 12771.0
23208 37.0 8.0 22.0 False 1 14.0 Санкт-Петербург 12387.0 27838.0
114 21.4 8.3 6.3 False 1 8.0 Санкт-Петербург 5791.0 27089.0
2309 62.4 8.4 41.0 False 2 9.0 Шушары 29448.0 23662.0
21505 35.3 8.5 16.1 False 1 27.0 Санкт-Петербург 15076.0 33977.0
17248 33.0 8.9 16.1 False 1 22.0 Санкт-Петербург 13671.0 33803.0

Всего имеется шесть записей, в которых жилая площадь составляет менее 6 м². Среди них две записи относятся к квартирам-студиям, а четыре — к обычным квартирам. Записи об обычных квартирах тем более представляются сомнительными, поскольку в трёх объектах из четырёх количество жилых комнат превышает 1.

Редактирование значений

В наборе данных имеются записи схожие с записями об объектах недвижимости, у которых жилая площадь меньше 6 м² и которые не позиционируются как квартиры-студии.

Запись № 13915. Объект недвижимости расположен на расстоянии 6521 м от центра Санкт-Петербурга. Найдём объекты, удалённые на таком же расстоянии.

In [49]:
data[columns][data['city_centers_nearest'] == 6521]
Out[49]:
total_area living_area kitchen_area studio rooms floors_total locality_name city_centers_nearest airports_nearest
13915 52.0 2.0 9.0 False 2 6.0 Санкт-Петербург 6521.0 32453.0
17058 48.0 26.0 8.0 False 2 5.0 Санкт-Петербург 6521.0 32453.0

Вероятно, была потеряна первая цифра в значении жилой площади. Заменим 2 м² на 22 м².

In [50]:
data.loc[13915, 'living_area'] = 22
data.loc[[13915], columns]
Out[50]:
total_area living_area kitchen_area studio rooms floors_total locality_name city_centers_nearest airports_nearest
13915 52.0 22.0 9.0 False 2 6.0 Санкт-Петербург 6521.0 32453.0

Запись № 3242. Объект недвижимости расположен на расстоянии 13 073 м от центра Санкт-Петербурга, на расстоянии 19 272 м от аэропорта в 17-этажном здании. Найдём объекты со схожими параметрами.

In [51]:
data[columns][(data['city_centers_nearest'] == 13073) &
              (data['airports_nearest'] == 19272) &
              (data['floors_total'] == 17)]
Out[51]:
total_area living_area kitchen_area studio rooms floors_total locality_name city_centers_nearest airports_nearest
796 36.0 16.5 10.0 False 1 17.0 Санкт-Петербург 13073.0 19272.0
3242 41.0 3.0 11.0 False 1 17.0 Санкт-Петербург 13073.0 19272.0
6890 55.0 35.0 10.0 False 2 17.0 Санкт-Петербург 13073.0 19272.0
12084 57.0 33.0 11.0 False 2 17.0 Санкт-Петербург 13073.0 19272.0
16530 66.0 35.8 10.6 False 2 17.0 Санкт-Петербург 13073.0 19272.0
22545 81.4 45.4 11.5 False 3 17.0 Санкт-Петербург 13073.0 19272.0

Схожим по данным является объект в записи № 796. Возможно, пропала первая цифра в значении жилой площади.
Заменим 3 м² на 13 м².

In [52]:
data.loc[3242, 'living_area'] = 13
data.loc[[3242], columns]
Out[52]:
total_area living_area kitchen_area studio rooms floors_total locality_name city_centers_nearest airports_nearest
3242 41.0 13.0 11.0 False 1 17.0 Санкт-Петербург 13073.0 19272.0

Запись № 23574. Объект недвижимости расположен на расстоянии 5975 м от центра Санкт-Петербурга. Найдём объекты, удалённые на таком же расстоянии.

In [53]:
data[columns][data['city_centers_nearest'] == 5975]
Out[53]:
total_area living_area kitchen_area studio rooms floors_total locality_name city_centers_nearest airports_nearest
411 151.0 85.0 23.0 False 3 8.0 Санкт-Петербург 5975.0 33255.0
3056 143.0 83.5 19.4 False 2 8.0 Санкт-Петербург 5975.0 33255.0
23574 139.0 3.0 16.0 False 3 8.0 Санкт-Петербург 5975.0 33255.0

Объекты недвижимости находятся либо в одном здании, либо в соседних 8-этажных зданиях. Вероятно, потерялась первая цифра (цифра 8) в значении жилой площади. Заменим 3 м² на 83 м².

In [54]:
data.loc[23574, 'living_area'] = 83
data.loc[[23574], columns]
Out[54]:
total_area living_area kitchen_area studio rooms floors_total locality_name city_centers_nearest airports_nearest
23574 139.0 83.0 16.0 False 3 8.0 Санкт-Петербург 5975.0 33255.0

Запись № 21943. Объект недвижимости расположен на расстоянии 11 270 м от центра Санкт-Петербурга. Найдём объекты, удалённые на таком же расстоянии.

In [55]:
data[columns][data['city_centers_nearest'] == 11270]
Out[55]:
total_area living_area kitchen_area studio rooms floors_total locality_name city_centers_nearest airports_nearest
6143 50.3 NaN 6.9 False 2 9.0 Санкт-Петербург 11270.0 29338.0
6667 50.4 30.3 9.5 False 2 9.0 Санкт-Петербург 11270.0 29338.0
11414 62.4 40.0 9.5 False 3 9.0 Санкт-Петербург 11270.0 29338.0
19873 50.3 28.3 7.0 False 2 9.0 Санкт-Петербург 11270.0 29338.0
21943 77.6 5.4 9.8 False 4 9.0 Санкт-Петербург 11270.0 29338.0

Поскольку в объекте недвижимости находятся 4 жилые комнаты, можно предположить, что в значении жилой площади положение запятой, отделяющей десятичную часть, сместилось на один знак влево. Заменим 5,4 м² на 54 м².

In [56]:
data.loc[21943, 'living_area'] = 54
data.loc[[21943], columns]
Out[56]:
total_area living_area kitchen_area studio rooms floors_total locality_name city_centers_nearest airports_nearest
21943 77.6 54.0 9.8 False 4 9.0 Санкт-Петербург 11270.0 29338.0

Запись № 17582. Объект недвижимости расположен на расстоянии 11 270 м от центра Санкт-Петербурга в 25-этажном здании. Найдём объекты со схожими параметрами.

In [57]:
data[columns][(data['city_centers_nearest'] == 11618) &
              (data['floors_total'] == 25)]
Out[57]:
total_area living_area kitchen_area studio rooms floors_total locality_name city_centers_nearest airports_nearest
959 35.0 NaN NaN False 1 25.0 Санкт-Петербург 11618.0 22735.0
7288 40.0 18.0 8.0 False 1 25.0 Санкт-Петербург 11618.0 22735.0
13574 38.9 17.4 11.9 False 1 25.0 Санкт-Петербург 11618.0 22735.0
17582 22.0 5.0 NaN True 0 25.0 Санкт-Петербург 11618.0 22735.0
21504 65.5 24.0 20.9 False 2 25.0 Санкт-Петербург 11618.0 22735.0
23111 26.1 16.0 NaN False 1 25.0 Санкт-Петербург 11618.0 22735.0

Схожим является объект в записи № 23111. Возможно, в значении жилой площади также была потеряна первая цифра.
Заменим 5 м² на 15 м².

In [58]:
data.loc[17582, 'living_area'] = 15
data.loc[[17582], columns]
Out[58]:
total_area living_area kitchen_area studio rooms floors_total locality_name city_centers_nearest airports_nearest
17582 22.0 15.0 NaN True 0 25.0 Санкт-Петербург 11618.0 22735.0

Запись № 21758. Объект недвижимости является квартирой-студией, расположен в Мурино в 24-этажном здании. Найдём объекты со схожими параметрами.

In [59]:
data[columns][(data['locality_name'] == 'Мурино') &
              data['studio'] &
              (data['floors_total'] == 24)]
Out[59]:
total_area living_area kitchen_area studio rooms floors_total locality_name city_centers_nearest airports_nearest
144 27.0 15.50 NaN True 0 24.0 Мурино NaN NaN
15109 24.4 13.56 NaN True 0 24.0 Мурино NaN NaN
21758 23.0 2.00 NaN True 0 24.0 Мурино NaN NaN

Вероятно, и в этом случае была утеряна первая цифра в значении жилой площади. Заменим 2 м² на 12 м².

In [60]:
data.loc[21758, 'living_area'] = 12
data.loc[[21758], columns]
Out[60]:
total_area living_area kitchen_area studio rooms floors_total locality_name city_centers_nearest airports_nearest
21758 23.0 12.0 NaN True 0 24.0 Мурино NaN NaN
In [61]:
data['living_area'].sort_values().unique()
Out[61]:
array([  6.  ,   6.5 ,   8.  ,   8.3 ,   8.4 ,   8.5 ,   8.9 ,   9.  ,
         9.1 ,   9.8 ,  10.  ,  10.08,  10.3 ,  10.4 ,  10.5 ,  10.52,
        10.55,  10.6 ,  10.7 ,  10.76,  10.8 ,  10.9 ,  10.93,  10.94,
        11.  ,  11.1 ,  11.15,  11.2 ,  11.3 ,  11.38,  11.4 ,  11.47,
        11.5 ,  11.6 ,  11.7 ,  11.79,  11.88,  11.9 ,  11.99,  12.  ,
        12.08,  12.1 ,  12.18,  12.2 ,  12.28,  12.3 ,  12.5 ,  12.6 ,
        12.7 ,  12.71,  12.79,  12.8 ,  12.81,  12.9 ,  13.  ,  13.05,
        13.09,  13.1 ,  13.15,  13.2 ,  13.27,  13.3 ,  13.32,  13.34,
        13.37,  13.4 ,  13.46,  13.5 ,  13.54,  13.56,  13.59,  13.6 ,
        13.62,  13.66,  13.7 ,  13.73,  13.76,  13.79,  13.8 ,  13.82,
        13.89,  13.9 ,  13.92,  14.  ,  14.01,  14.02,  14.03,  14.06,
        14.08,  14.1 ,  14.11,  14.16,  14.17,  14.19,  14.2 ,  14.22,
        14.23,  14.25,  14.28,  14.3 ,  14.31,  14.35,  14.37,  14.38,
        14.39,  14.4 ,  14.41,  14.45,  14.46,  14.47,  14.5 ,  14.51,
        14.55,  14.56,  14.57,  14.58,  14.59,  14.6 ,  14.62,  14.64,
        14.65,  14.69,  14.7 ,  14.71,  14.73,  14.74,  14.77,  14.8 ,
        14.85,  14.89,  14.9 ,  14.91,  14.92,  14.95,  15.  ,  15.01,
        15.02,  15.03,  15.04,  15.05,  15.06,  15.07,  15.08,  15.1 ,
        15.11,  15.12,  15.13,  15.15,  15.16,  15.18,  15.2 ,  15.25,
        15.26,  15.3 ,  15.31,  15.32,  15.33,  15.34,  15.35,  15.36,
        15.37,  15.38,  15.4 ,  15.41,  15.42,  15.43,  15.45,  15.46,
        15.5 ,  15.53,  15.54,  15.55,  15.58,  15.6 ,  15.61,  15.62,
        15.64,  15.65,  15.66,  15.7 ,  15.71,  15.72,  15.77,  15.78,
        15.79,  15.8 ,  15.82,  15.85,  15.86,  15.88,  15.89,  15.9 ,
        15.91,  15.92,  15.93,  15.96,  16.  ,  16.04,  16.06,  16.07,
        16.08,  16.09,  16.1 ,  16.11,  16.12,  16.15,  16.16,  16.18,
        16.2 ,  16.22,  16.26,  16.29,  16.3 ,  16.31,  16.32,  16.4 ,
        16.41,  16.42,  16.47,  16.5 ,  16.51,  16.52,  16.55,  16.58,
        16.59,  16.6 ,  16.61,  16.62,  16.63,  16.66,  16.68,  16.69,
        16.7 ,  16.71,  16.72,  16.74,  16.76,  16.8 ,  16.83,  16.84,
        16.88,  16.9 ,  16.91,  16.92,  16.93,  16.94,  16.95,  16.96,
        16.97,  16.98,  17.  ,  17.01,  17.03,  17.04,  17.05,  17.07,
        17.08,  17.1 ,  17.11,  17.12,  17.14,  17.19,  17.2 ,  17.22,
        17.25,  17.26,  17.27,  17.3 ,  17.33,  17.34,  17.35,  17.36,
        17.38,  17.4 ,  17.43,  17.45,  17.48,  17.49,  17.5 ,  17.51,
        17.53,  17.6 ,  17.62,  17.65,  17.66,  17.7 ,  17.71,  17.73,
        17.78,  17.8 ,  17.82,  17.83,  17.84,  17.85,  17.87,  17.9 ,
        17.92,  17.93,  17.95,  17.97,  18.  ,  18.02,  18.03,  18.04,
        18.08,  18.09,  18.1 ,  18.11,  18.12,  18.14,  18.15,  18.16,
        18.19,  18.2 ,  18.23,  18.28,  18.3 ,  18.33,  18.34,  18.35,
        18.39,  18.4 ,  18.44,  18.46,  18.47,  18.5 ,  18.55,  18.57,
        18.6 ,  18.61,  18.62,  18.7 ,  18.72,  18.79,  18.8 ,  18.83,
        18.84,  18.86,  18.88,  18.9 ,  18.93,  18.95,  19.  ,  19.03,
        19.1 ,  19.15,  19.2 ,  19.22,  19.3 ,  19.35,  19.4 ,  19.5 ,
        19.52,  19.55,  19.6 ,  19.65,  19.7 ,  19.8 ,  19.9 ,  19.95,
        20.  ,  20.02,  20.03,  20.1 ,  20.11,  20.13,  20.19,  20.2 ,
        20.26,  20.3 ,  20.31,  20.36,  20.39,  20.4 ,  20.46,  20.5 ,
        20.52,  20.55,  20.6 ,  20.67,  20.7 ,  20.74,  20.75,  20.77,
        20.8 ,  20.9 ,  20.97,  21.  ,  21.04,  21.06,  21.08,  21.09,
        21.1 ,  21.11,  21.12,  21.15,  21.2 ,  21.28,  21.3 ,  21.4 ,
        21.5 ,  21.53,  21.59,  21.6 ,  21.65,  21.68,  21.7 ,  21.77,
        21.8 ,  21.9 ,  22.  ,  22.04,  22.1 ,  22.15,  22.2 ,  22.3 ,
        22.35,  22.37,  22.4 ,  22.43,  22.45,  22.5 ,  22.57,  22.6 ,
        22.62,  22.7 ,  22.8 ,  22.81,  22.9 ,  23.  ,  23.1 ,  23.19,
        23.2 ,  23.3 ,  23.4 ,  23.43,  23.5 ,  23.6 ,  23.7 ,  23.77,
        23.8 ,  23.9 ,  24.  ,  24.1 ,  24.2 ,  24.3 ,  24.4 ,  24.42,
        24.5 ,  24.6 ,  24.64,  24.7 ,  24.75,  24.77,  24.8 ,  24.83,
        24.86,  24.89,  24.9 ,  25.  ,  25.1 ,  25.2 ,  25.3 ,  25.38,
        25.4 ,  25.41,  25.44,  25.5 ,  25.6 ,  25.7 ,  25.8 ,  25.81,
        25.9 ,  25.95,  25.97,  26.  ,  26.1 ,  26.13,  26.2 ,  26.21,
        26.28,  26.29,  26.3 ,  26.4 ,  26.5 ,  26.51,  26.6 ,  26.61,
        26.7 ,  26.75,  26.79,  26.8 ,  26.87,  26.9 ,  26.94,  27.  ,
        27.05,  27.06,  27.1 ,  27.12,  27.2 ,  27.22,  27.25,  27.29,
        27.3 ,  27.33,  27.38,  27.4 ,  27.42,  27.43,  27.46,  27.5 ,
        27.51,  27.57,  27.6 ,  27.67,  27.69,  27.7 ,  27.75,  27.77,
        27.8 ,  27.88,  27.89,  27.9 ,  27.92,  27.95,  28.  ,  28.01,
        28.02,  28.07,  28.09,  28.1 ,  28.14,  28.15,  28.18,  28.2 ,
        28.23,  28.26,  28.3 ,  28.31,  28.33,  28.34,  28.36,  28.4 ,
        28.42,  28.43,  28.45,  28.47,  28.48,  28.5 ,  28.54,  28.55,
        28.6 ,  28.66,  28.7 ,  28.71,  28.73,  28.77,  28.8 ,  28.81,
        28.84,  28.85,  28.86,  28.88,  28.9 ,  28.98,  29.  ,  29.01,
        29.08,  29.1 ,  29.13,  29.16,  29.2 ,  29.21,  29.22,  29.27,
        29.3 ,  29.34,  29.38,  29.4 ,  29.41,  29.43,  29.48,  29.5 ,
        29.52,  29.55,  29.56,  29.6 ,  29.61,  29.67,  29.7 ,  29.72,
        29.74,  29.77,  29.78,  29.8 ,  29.81,  29.83,  29.84,  29.85,
        29.9 ,  29.92,  30.  ,  30.01,  30.04,  30.05,  30.08,  30.1 ,
        30.12,  30.15,  30.16,  30.17,  30.2 ,  30.29,  30.3 ,  30.31,
        30.35,  30.39,  30.4 ,  30.5 ,  30.52,  30.55,  30.57,  30.59,
        30.6 ,  30.61,  30.62,  30.7 ,  30.72,  30.75,  30.8 ,  30.81,
        30.82,  30.83,  30.89,  30.9 ,  30.92,  31.  ,  31.01,  31.04,
        31.05,  31.07,  31.1 ,  31.12,  31.18,  31.2 ,  31.26,  31.29,
        31.3 ,  31.38,  31.4 ,  31.41,  31.42,  31.43,  31.44,  31.47,
        31.48,  31.5 ,  31.51,  31.52,  31.55,  31.6 ,  31.61,  31.62,
        31.64,  31.65,  31.7 ,  31.71,  31.74,  31.77,  31.8 ,  31.81,
        31.9 ,  32.  ,  32.02,  32.04,  32.05,  32.06,  32.08,  32.1 ,
        32.2 ,  32.26,  32.3 ,  32.35,  32.37,  32.38,  32.4 ,  32.46,
        32.5 ,  32.6 ,  32.61,  32.62,  32.7 ,  32.71,  32.73,  32.79,
        32.8 ,  32.84,  32.9 ,  32.95,  33.  ,  33.03,  33.06,  33.08,
        33.1 ,  33.18,  33.2 ,  33.26,  33.3 ,  33.36,  33.4 ,  33.47,
        33.5 ,  33.57,  33.6 ,  33.63,  33.67,  33.7 ,  33.72,  33.73,
        33.8 ,  33.87,  33.9 ,  33.92,  34.  ,  34.1 ,  34.14,  34.2 ,
        34.29,  34.3 ,  34.32,  34.37,  34.4 ,  34.41,  34.44,  34.5 ,
        34.51,  34.6 ,  34.63,  34.7 ,  34.76,  34.79,  34.8 ,  34.87,
        34.88,  34.9 ,  35.  ,  35.01,  35.05,  35.07,  35.1 ,  35.17,
        35.2 ,  35.3 ,  35.33,  35.38,  35.4 ,  35.48,  35.5 ,  35.55,
        35.6 ,  35.61,  35.7 ,  35.74,  35.76,  35.77,  35.8 ,  35.81,
        35.88,  35.89,  35.9 ,  35.91,  35.92,  36.  ,  36.04,  36.07,
        36.1 ,  36.15,  36.2 ,  36.27,  36.3 ,  36.35,  36.4 ,  36.45,
        36.5 ,  36.57,  36.6 ,  36.7 ,  36.76,  36.79,  36.8 ,  36.81,
        36.86,  36.9 ,  36.95,  37.  ,  37.1 ,  37.13,  37.2 ,  37.28,
        37.3 ,  37.4 ,  37.5 ,  37.52,  37.6 ,  37.66,  37.7 ,  37.74,
        37.8 ,  37.9 ,  38.  ,  38.03,  38.05,  38.07,  38.1 ,  38.18,
        38.2 ,  38.3 ,  38.33,  38.39,  38.4 ,  38.5 ,  38.6 ,  38.7 ,
        38.73,  38.8 ,  38.9 ,  38.91,  38.95,  38.99,  39.  ,  39.07,
        39.1 ,  39.18,  39.2 ,  39.3 ,  39.4 ,  39.41,  39.5 ,  39.59,
        39.6 ,  39.62,  39.66,  39.7 ,  39.71,  39.78,  39.8 ,  39.85,
        39.9 ,  40.  ,  40.06,  40.1 ,  40.2 ,  40.3 ,  40.32,  40.39,
        40.4 ,  40.43,  40.5 ,  40.57,  40.59,  40.6 ,  40.61,  40.7 ,
        40.79,  40.8 ,  40.83,  40.9 ,  40.92,  40.95,  41.  ,  41.05,
        41.06,  41.08,  41.1 ,  41.17,  41.19,  41.2 ,  41.3 ,  41.34,
        41.35,  41.4 ,  41.44,  41.5 ,  41.6 ,  41.69,  41.7 ,  41.8 ,
        41.9 ,  41.92,  41.98,  42.  ,  42.1 ,  42.17,  42.2 ,  42.26,
        42.3 ,  42.31,  42.4 ,  42.41,  42.43,  42.48,  42.5 ,  42.54,
        42.55,  42.6 ,  42.7 ,  42.8 ,  42.9 ,  42.91,  43.  ,  43.05,
        43.1 ,  43.15,  43.2 ,  43.3 ,  43.32,  43.4 ,  43.45,  43.46,
        43.5 ,  43.6 ,  43.62,  43.63,  43.7 ,  43.71,  43.78,  43.8 ,
        43.81,  43.83,  43.89,  43.9 ,  43.92,  44.  ,  44.04,  44.05,
        44.1 ,  44.13,  44.15,  44.2 ,  44.3 ,  44.4 ,  44.5 ,  44.56,
        44.6 ,  44.7 ,  44.8 ,  44.9 ,  44.91,  44.99,  45.  ,  45.1 ,
        45.11,  45.13,  45.18,  45.2 ,  45.23,  45.3 ,  45.34,  45.38,
        45.4 ,  45.5 ,  45.6 ,  45.7 ,  45.72,  45.8 ,  45.82,  45.85,
        45.86,  45.9 ,  45.92,  45.95,  46.  ,  46.01,  46.05,  46.1 ,
        46.13,  46.14,  46.15,  46.2 ,  46.3 ,  46.4 ,  46.5 ,  46.57,
        46.6 ,  46.64,  46.7 ,  46.75,  46.8 ,  46.9 ,  47.  ,  47.1 ,
        47.11,  47.2 ,  47.24,  47.3 ,  47.37,  47.4 ,  47.43,  47.5 ,
        47.53,  47.6 ,  47.68,  47.7 ,  47.8 ,  47.9 ,  48.  ,  48.05,
        48.1 ,  48.13,  48.2 ,  48.25,  48.3 ,  48.35,  48.36,  48.38,
        48.4 ,  48.41,  48.42,  48.45,  48.46,  48.48,  48.49,  48.5 ,
        48.6 ,  48.62,  48.7 ,  48.8 ,  48.84,  48.88,  48.9 ,  48.93,
        48.94,  49.  ,  49.1 ,  49.2 ,  49.25,  49.27,  49.28,  49.3 ,
        49.33,  49.4 ,  49.46,  49.5 ,  49.58,  49.6 ,  49.7 ,  49.74,
        49.8 ,  49.87,  49.9 ,  49.98,  50.  ,  50.02,  50.08,  50.1 ,
        50.16,  50.2 ,  50.25,  50.26,  50.28,  50.3 ,  50.34,  50.4 ,
        50.47,  50.5 ,  50.6 ,  50.64,  50.7 ,  50.8 ,  50.81,  50.9 ,
        51.  ,  51.07,  51.1 ,  51.2 ,  51.3 ,  51.4 ,  51.5 ,  51.6 ,
        51.7 ,  51.76,  51.78,  51.8 ,  51.88,  51.9 ,  52.  ,  52.02,
        52.1 ,  52.2 ,  52.21,  52.26,  52.3 ,  52.4 ,  52.5 ,  52.53,
        52.6 ,  52.65,  52.7 ,  52.77,  52.8 ,  52.9 ,  52.94,  53.  ,
        53.1 ,  53.15,  53.17,  53.2 ,  53.3 ,  53.31,  53.33,  53.35,
        53.4 ,  53.5 ,  53.6 ,  53.7 ,  53.8 ,  53.9 ,  54.  ,  54.09,
        54.1 ,  54.13,  54.2 ,  54.3 ,  54.4 ,  54.43,  54.48,  54.5 ,
        54.6 ,  54.7 ,  54.74,  54.8 ,  54.9 ,  55.  ,  55.1 ,  55.2 ,
        55.22,  55.3 ,  55.35,  55.38,  55.4 ,  55.5 ,  55.6 ,  55.7 ,
        55.8 ,  55.84,  55.9 ,  56.  ,  56.1 ,  56.12,  56.2 ,  56.3 ,
        56.4 ,  56.5 ,  56.53,  56.6 ,  56.7 ,  56.8 ,  56.86,  56.9 ,
        57.  ,  57.1 ,  57.2 ,  57.3 ,  57.35,  57.4 ,  57.5 ,  57.51,
        57.6 ,  57.7 ,  57.75,  57.8 ,  57.9 ,  58.  ,  58.1 ,  58.18,
        58.2 ,  58.3 ,  58.4 ,  58.44,  58.5 ,  58.6 ,  58.63,  58.7 ,
        58.8 ,  58.82,  59.  ,  59.1 ,  59.12,  59.2 ,  59.3 ,  59.4 ,
        59.5 ,  59.6 ,  59.7 ,  59.8 ,  59.9 ,  60.  ,  60.1 ,  60.2 ,
        60.3 ,  60.33,  60.4 ,  60.5 ,  60.6 ,  60.7 ,  60.77,  60.8 ,
        60.9 ,  61.  ,  61.1 ,  61.2 ,  61.3 ,  61.35,  61.4 ,  61.5 ,
        61.6 ,  61.7 ,  61.8 ,  61.9 ,  62.  ,  62.1 ,  62.2 ,  62.3 ,
        62.4 ,  62.5 ,  62.6 ,  62.7 ,  62.75,  62.8 ,  62.9 ,  63.  ,
        63.1 ,  63.2 ,  63.3 ,  63.31,  63.4 ,  63.5 ,  63.6 ,  63.7 ,
        63.72,  63.8 ,  63.9 ,  64.  ,  64.1 ,  64.2 ,  64.3 ,  64.32,
        64.4 ,  64.5 ,  64.6 ,  64.7 ,  64.8 ,  64.9 ,  65.  ,  65.3 ,
        65.4 ,  65.5 ,  65.6 ,  65.7 ,  65.72,  65.8 ,  65.9 ,  65.93,
        66.  ,  66.01,  66.1 ,  66.2 ,  66.22,  66.24,  66.3 ,  66.4 ,
        66.5 ,  66.6 ,  66.7 ,  66.8 ,  66.9 ,  66.99,  67.  ,  67.01,
        67.1 ,  67.2 ,  67.3 ,  67.4 ,  67.5 ,  67.6 ,  67.8 ,  67.81,
        67.9 ,  68.  ,  68.1 ,  68.3 ,  68.4 ,  68.48,  68.5 ,  68.6 ,
        68.7 ,  68.8 ,  68.9 ,  69.  ,  69.1 ,  69.2 ,  69.28,  69.3 ,
        69.5 ,  69.6 ,  69.7 ,  69.75,  69.8 ,  69.9 ,  70.  ,  70.1 ,
        70.3 ,  70.4 ,  70.48,  70.5 ,  70.6 ,  70.7 ,  70.9 ,  71.  ,
        71.1 ,  71.2 ,  71.3 ,  71.4 ,  71.5 ,  71.7 ,  71.72,  71.9 ,
        72.  ,  72.1 ,  72.2 ,  72.3 ,  72.4 ,  72.5 ,  72.52,  72.6 ,
        72.7 ,  72.79,  72.8 ,  73.  ,  73.1 ,  73.2 ,  73.3 ,  73.4 ,
        73.5 ,  73.6 ,  73.8 ,  73.9 ,  74.  ,  74.1 ,  74.16,  74.2 ,
        74.3 ,  74.4 ,  74.6 ,  74.8 ,  74.99,  75.  ,  75.1 ,  75.2 ,
        75.25,  75.4 ,  75.5 ,  75.6 ,  75.7 ,  75.8 ,  75.83,  76.  ,
        76.1 ,  76.2 ,  76.3 ,  76.4 ,  76.5 ,  76.65,  76.7 ,  76.8 ,
        76.9 ,  77.  ,  77.1 ,  77.2 ,  77.3 ,  77.35,  77.4 ,  77.5 ,
        77.6 ,  77.61,  77.71,  77.8 ,  78.  ,  78.03,  78.4 ,  78.5 ,
        78.6 ,  78.9 ,  79.  ,  79.2 ,  79.28,  79.3 ,  79.34,  79.4 ,
        79.42,  79.5 ,  79.7 ,  79.74,  80.  ,  80.1 ,  80.2 ,  80.3 ,
        80.39,  80.5 ,  80.62,  80.7 ,  80.8 ,  80.9 ,  81.  ,  81.1 ,
        81.3 ,  81.4 ,  81.5 ,  81.6 ,  81.66,  81.7 ,  81.9 ,  82.  ,
        82.05,  82.1 ,  82.2 ,  82.3 ,  82.4 ,  82.55,  82.8 ,  82.9 ,
        83.  ,  83.2 ,  83.5 ,  83.6 ,  83.7 ,  83.8 ,  84.  ,  84.1 ,
        84.2 ,  84.5 ,  84.6 ,  84.69,  84.7 ,  85.  ,  85.1 ,  85.2 ,
        85.3 ,  85.6 ,  86.  ,  86.1 ,  86.2 ,  86.6 ,  86.7 ,  87.  ,
        87.2 ,  87.23,  87.5 ,  87.7 ,  87.8 ,  88.  ,  88.1 ,  88.2 ,
        88.3 ,  89.  ,  89.1 ,  89.11,  89.2 ,  89.3 ,  89.4 ,  89.5 ,
        89.6 ,  89.7 ,  89.9 ,  90.  ,  90.2 ,  90.6 ,  90.7 ,  91.  ,
        91.2 ,  91.24,  91.7 ,  91.77,  91.8 ,  92.  ,  92.1 ,  92.3 ,
        92.34,  92.5 ,  92.6 ,  92.7 ,  92.8 ,  92.9 ,  93.  ,  93.1 ,
        93.2 ,  93.5 ,  93.6 ,  94.  ,  94.1 ,  94.4 ,  94.54,  94.8 ,
        94.89,  94.9 ,  95.  ,  95.1 ,  95.2 ,  95.4 ,  95.41,  95.45,
        95.6 ,  95.7 ,  95.9 ,  96.  ,  96.3 ,  96.4 ,  96.6 ,  96.7 ,
        97.  ,  97.2 ,  97.3 ,  97.6 ,  98.  ,  98.2 ,  98.5 ,  98.7 ,
        98.9 ,  99.  ,  99.1 ,  99.21,  99.3 ,  99.5 ,  99.6 ,  99.7 ,
        99.8 ,  99.9 , 100.  , 100.1 , 100.23, 100.4 , 100.7 , 100.9 ,
       101.  , 101.2 , 101.54, 101.82, 102.  , 102.2 , 102.3 , 102.5 ,
       102.8 , 103.  , 103.1 , 103.3 , 103.6 , 103.7 , 103.8 , 104.  ,
       104.1 , 104.2 , 104.76, 104.8 , 105.  , 105.3 , 105.8 , 106.  ,
       106.1 , 106.2 , 106.4 , 106.5 , 107.  , 107.03, 107.6 , 108.  ,
       108.8 , 109.  , 109.4 , 109.51, 110.  , 110.3 , 110.4 , 110.8 ,
       111.  , 111.1 , 111.6 , 111.86, 112.  , 112.2 , 112.4 , 112.7 ,
       113.  , 114.  , 114.7 , 114.8 , 115.  , 115.5 , 115.8 , 116.  ,
       116.2 , 117.  , 117.1 , 117.3 , 117.4 , 118.4 , 118.5 , 118.9 ,
       119.  , 119.3 , 119.5 , 119.9 , 120.  , 121.  , 121.6 , 122.  ,
       122.1 , 123.  , 123.1 , 123.27, 123.6 , 123.9 , 124.  , 124.9 ,
       125.  , 125.1 , 125.5 , 125.7 , 125.9 , 126.  , 126.4 , 126.6 ,
       127.  , 127.7 , 128.  , 129.  , 130.  , 130.3 , 131.  , 131.5 ,
       132.  , 133.  , 133.4 , 134.  , 134.7 , 134.8 , 136.  , 136.1 ,
       136.2 , 137.7 , 138.8 , 139.  , 139.4 , 139.8 , 140.  , 141.  ,
       142.  , 143.  , 144.5 , 144.6 , 145.  , 145.4 , 145.5 , 145.9 ,
       147.  , 147.2 , 148.  , 148.6 , 149.4 , 150.  , 150.4 , 150.8 ,
       151.  , 151.1 , 151.4 , 151.6 , 152.  , 153.  , 153.9 , 154.  ,
       154.7 , 155.  , 155.1 , 155.5 , 157.  , 159.2 , 159.5 , 159.6 ,
       159.9 , 160.  , 160.1 , 160.6 , 161.4 , 162.  , 163.2 , 163.5 ,
       164.3 , 164.7 , 165.  , 165.5 , 166.7 , 167.  , 168.3 , 170.  ,
       170.8 , 171.  , 174.  , 174.3 , 175.  , 176.2 , 176.6 , 177.  ,
       177.3 , 179.  , 179.2 , 180.  , 181.8 , 182.  , 182.8 , 183.  ,
       183.7 , 184.  , 184.9 , 187.  , 187.9 , 188.7 , 189.4 , 190.  ,
       193.  , 193.5 , 194.  , 195.  , 198.  , 199.  , 200.  , 204.  ,
       211.  , 216.  , 218.  , 220.  , 222.  , 225.9 , 230.  , 239.4 ,
       248.5 , 248.7 , 250.  , 255.7 , 258.  , 260.  , 264.5 , 274.  ,
       279.6 , 300.  , 301.5 , 312.5 , 322.3 , 332.  , 347.5 , 409.  ,
       409.7 ,    nan])

Жилая площадь у всех объектов недвижимости составляет не менее 6 м².

Общая площадь меньше или равна сумме площадей: жилой и кухни¶

Значения жилой площади, площади кухни должны согласоваться с общей площадью объекта недвижимости. Сумма площадей помещений не может превышать общую площадь. Кроме того, сумма площадей жилых помещений и кухни не может быть равна общей площади объекта недвижимости, поскольку помимо кухни в квартире имеются и другие вспомогательные помещения.

In [62]:
columns = ['total_area', 'living_area', 'kitchen_area',
           'rooms', 'floors_total', 'locality_name']

data[columns][(data['living_area'] + data['kitchen_area']).round(2) >= \
              data['total_area']].sort_values('living_area')
Out[62]:
total_area living_area kitchen_area rooms floors_total locality_name
8873 20.00 14.00 6.00 1 7.0 Санкт-Петербург
22869 25.00 14.00 11.00 1 5.0 Санкт-Петербург
10725 25.60 14.17 14.17 1 18.0 Мурино
7755 20.67 14.95 14.95 1 24.0 Мурино
2797 23.00 15.00 8.00 1 7.0 Всеволожск
... ... ... ... ... ... ...
8211 93.00 82.00 14.50 3 16.0 Санкт-Петербург
12634 141.20 106.40 34.80 3 7.0 Санкт-Петербург
4293 156.00 115.00 41.00 4 5.0 Санкт-Петербург
12234 138.50 118.50 20.00 4 9.0 Санкт-Петербург
18164 146.80 128.00 18.80 3 16.0 Санкт-Петербург

135 rows × 6 columns

Таких объектов оказалось 135.

Удаление записей

Поскольку не представляется возможным выяснить, значения каких признаков (общей площади, жилой площади, площади кухни) были заполнены ошибочно, записи с несогласующимися значениями необходимо удалить.

In [63]:
data.drop(index=data[(data['living_area'] + data['kitchen_area']).round(2) >= \
                     data['total_area']].index,
          inplace=True)

len(data[(data['living_area'] + data['kitchen_area']).round(2) >= \
         data['total_area']])
Out[63]:
0

Маленькая площадь вспомогательных помещений¶

Однако недостаточно потребовать, чтобы общая площадь была больше суммы площадей: жилой и кухни. Важное значение приобретает разность этих величин, поскольку она представляет собой площадь, приходящуюся на остальные вспомогательные помещения, кроме кухни. Необходимо задать пороговое значение, меньше которого не может быть разность общей площади и суммы площадей: жилой и кухни. Таким критерием может стать площадь, отведённая под вспомогательные помещения в квартирах, которые позиционируются как квартиры-студии.

In [64]:
data.loc[data['studio'], 'kitchen_area'].unique()
Out[64]:
array([nan])

В объявлениях о продаже квартир-студий не указывается информация о площади кухни. В таких объектах недвижимости зачастую под кухню отводится зона на площади жилого помещения. Кухня оформляется как кухня-ниша. Однако туалет с ванной (душевой) является изолированным вспомогательным помещением.

Узнаем, какова минимальная площадь такого помещения среди опубликованных объявлений.

Заполним значения площади кухни в записях, относящихся к квартирам-студиям, значением 0.

In [65]:
data.loc[data['studio'], 'kitchen_area'] = data['kitchen_area'].fillna(0)
data.loc[data['studio'], 'kitchen_area'].unique()
Out[65]:
array([0.])

Введем дополнительный признак — площадь вспомогательных помещений (без учёта площади кухни) utility_rooms_area.

In [66]:
data['utility_rooms_area'] = \
    data['total_area'] - data['living_area'] - data['kitchen_area']
data['utility_rooms_area'] = data['utility_rooms_area'].round(2)
In [67]:
data.info()
<class 'pandas.core.frame.DataFrame'>
Index: 23560 entries, 0 to 23698
Data columns (total 24 columns):
 #   Column                Non-Null Count  Dtype  
---  ------                --------------  -----  
 0   total_images          23560 non-null  int64  
 1   last_price            23560 non-null  float64
 2   total_area            23560 non-null  float64
 3   first_day_exposition  23560 non-null  object 
 4   rooms                 23560 non-null  int64  
 5   ceiling_height        14417 non-null  float64
 6   floors_total          23474 non-null  float64
 7   living_area           21657 non-null  float64
 8   floor                 23560 non-null  int64  
 9   is_apartment          2747 non-null   object 
 10  studio                23560 non-null  bool   
 11  open_plan             23560 non-null  bool   
 12  kitchen_area          21432 non-null  float64
 13  balcony               12100 non-null  float64
 14  locality_name         23511 non-null  object 
 15  airports_nearest      18070 non-null  float64
 16  city_centers_nearest  18093 non-null  float64
 17  parks_around_3000     18094 non-null  float64
 18  parks_nearest         8037 non-null   float64
 19  ponds_around_3000     18094 non-null  float64
 20  ponds_nearest         9076 non-null   float64
 21  days_exposition       20396 non-null  float64
 22  locality_type         23511 non-null  object 
 23  utility_rooms_area    20983 non-null  float64
dtypes: bool(2), float64(15), int64(3), object(4)
memory usage: 4.7+ MB

Выведем записи о квартирах-студиях, которые характеризуются минимальным значением признака utility_rooms_area.

In [68]:
columns = ['total_area', 'living_area', 'kitchen_area', 'rooms', 'studio',
           'floors_total', 'locality_name', 'utility_rooms_area']

data[columns][(data['studio']) &
              (data['living_area'].notna())] \
              .sort_values(by='utility_rooms_area').head()
Out[68]:
total_area living_area kitchen_area rooms studio floors_total locality_name utility_rooms_area
12996 18.00 16.00 0.0 0 True 5.0 Санкт-Петербург 2.00
440 27.11 24.75 0.0 0 True 17.0 Санкт-Петербург 2.36
8683 32.50 29.90 0.0 1 True 23.0 Санкт-Петербург 2.60
8755 18.80 15.80 0.0 0 True 19.0 Санкт-Петербург 3.00
6225 28.00 25.00 0.0 0 True 25.0 Санкт-Петербург 3.00

Значения признака utility_rooms_area для квартир-студий начинаются с 2 м². Это означает, что минимальная площадь, которую требуется отвести под помещение туалета и ванной (душевой), должна составлять не менее 2 м².

Установим критерий, что площадь вспомогательных помещений (кроме кухни) не может быть меньше 2 м². Обоснованность этого критерия заключается ещё и в том, что могут существовать квартиры, в которых была осуществлена перепланировка: расширена жилая площадь и площадь кухни. Однако в связи с тем, что помещение туалета и ванной (душевой) должно быть изолировано, ожидается, что в квартире будет отведено под него помещение хотя бы минимальной площади, как это может быть сделано в квартире-студии.

Обзор значений

Проверим, есть ли объекты недвижимости, которые не удовлетворяют установленному критерию.

In [69]:
data[columns][data['utility_rooms_area'] < 2].sort_values('utility_rooms_area')
Out[69]:
total_area living_area kitchen_area rooms studio floors_total locality_name utility_rooms_area
14352 35.20 29.00 6.00 1 False 9.0 Выборг 0.20
10453 38.00 30.00 7.78 1 False 5.0 Санкт-Петербург 0.22
23108 33.95 21.68 12.00 1 False 19.0 Мурино 0.27
12271 69.00 55.00 13.73 2 False 20.0 Мурино 0.27
9138 23.29 21.00 2.00 1 False 3.0 Санкт-Петербург 0.29
... ... ... ... ... ... ... ... ...
12900 76.60 60.00 15.00 2 False 17.0 Санкт-Петербург 1.60
14031 37.60 24.00 12.00 1 False 7.0 Санкт-Петербург 1.60
21106 52.10 44.40 6.00 3 False 14.0 Санкт-Петербург 1.70
18750 34.50 24.00 8.80 1 False 25.0 Санкт-Петербург 1.70
20661 31.60 17.80 12.00 1 False 12.0 Санкт-Петербург 1.80

68 rows × 8 columns

Таких объектов оказалось 68.

Удаление записей

Поскольку не представляется возможным выяснить, значения каких признаков (общей площади, жилой площади, площади кухни) были заполнены ошибочно, записи с несогласующимися значениями необходимо удалить.

In [70]:
data.drop(index=data[data['utility_rooms_area'] < 2].index,
          inplace=True)

len(data[data['utility_rooms_area'] < 2])
Out[70]:
0

Обзор значений

Теперь проверим, есть ли среди объектов недвижимости, не являющихся квартирами-студиями, такие объекты, у которых разница между общей площадью и жилой площадью уже меньше 2 м².

In [71]:
data[~data['studio'] & ((data['total_area'] - data['living_area']).round(2) < 2)]
Out[71]:
total_images last_price total_area first_day_exposition rooms ceiling_height floors_total living_area floor is_apartment studio open_plan kitchen_area balcony locality_name airports_nearest city_centers_nearest parks_around_3000 parks_nearest ponds_around_3000 ponds_nearest days_exposition locality_type utility_rooms_area
2959 9 2550000.0 32.00 2017-12-02T00:00:00 1 NaN 14.0 30.20 13 False False False NaN 1.0 Кудрово NaN NaN NaN NaN NaN NaN 157.0 деревня NaN
9861 10 2350000.0 25.00 2017-12-03T00:00:00 0 NaN 22.0 25.00 17 NaN False True NaN 2.0 Мурино NaN NaN NaN NaN NaN NaN 13.0 посёлок NaN
10606 14 2950000.0 25.27 2017-11-17T00:00:00 0 NaN 25.0 25.00 11 NaN False True NaN 1.0 Санкт-Петербург 11405.0 13222.0 0.0 NaN 1.0 623.0 51.0 город NaN
12691 1 3700000.0 24.20 2017-11-10T00:00:00 0 NaN 19.0 24.20 13 NaN False True NaN 1.0 Санкт-Петербург 17837.0 16840.0 0.0 NaN 2.0 210.0 74.0 город NaN
20256 5 13351000.0 102.70 2018-07-03T00:00:00 6 3.4 4.0 101.00 1 NaN False False NaN NaN Санкт-Петербург 24477.0 5464.0 2.0 519.0 0.0 NaN 229.0 город NaN
21802 6 1737000.0 17.78 2018-11-22T00:00:00 1 2.6 9.0 15.89 1 NaN False False NaN NaN Санкт-Петербург 13289.0 12086.0 0.0 NaN 0.0 NaN 66.0 город NaN

Удаление значений

Поскольку для этих записей также нет возможности установить, значения каких признаков (общей площади, жилой площади) были заполнены ошибочно, записи с несогласующимися значениями необходимо удалить.

In [72]:
data.drop(index=data[~data['studio'] &
                     ((data['total_area'] - data['living_area']).round(2) < 2)].index,
          inplace=True)

len(data[~data['studio'] & ((data['total_area'] - data['living_area']).round(2) < 2)])
Out[72]:
0

А теперь удалим вспомогательный признак. Также уберём введённое значение площади кухни "0" для записей, относящихся к квартирам-студиям.

In [73]:
data = data.drop(columns='utility_rooms_area')
data['kitchen_area'].replace(0, np.nan, inplace=True)
data.info()
<class 'pandas.core.frame.DataFrame'>
Index: 23486 entries, 0 to 23698
Data columns (total 23 columns):
 #   Column                Non-Null Count  Dtype  
---  ------                --------------  -----  
 0   total_images          23486 non-null  int64  
 1   last_price            23486 non-null  float64
 2   total_area            23486 non-null  float64
 3   first_day_exposition  23486 non-null  object 
 4   rooms                 23486 non-null  int64  
 5   ceiling_height        14374 non-null  float64
 6   floors_total          23400 non-null  float64
 7   living_area           21583 non-null  float64
 8   floor                 23486 non-null  int64  
 9   is_apartment          2739 non-null   object 
 10  studio                23486 non-null  bool   
 11  open_plan             23486 non-null  bool   
 12  kitchen_area          21215 non-null  float64
 13  balcony               12068 non-null  float64
 14  locality_name         23437 non-null  object 
 15  airports_nearest      18021 non-null  float64
 16  city_centers_nearest  18044 non-null  float64
 17  parks_around_3000     18045 non-null  float64
 18  parks_nearest         8023 non-null   float64
 19  ponds_around_3000     18045 non-null  float64
 20  ponds_nearest         9049 non-null   float64
 21  days_exposition       20331 non-null  float64
 22  locality_type         23437 non-null  object 
dtypes: bool(2), float64(14), int64(3), object(4)
memory usage: 4.0+ MB

Значения в признаках total_area, living_area и kitchen_area являются согласованными и отвечают установленному критерию.

Среди значений площади кухни есть одно подозрительно маленькое значение — 1,3 м². Для объекта недвижимости с такой площадью кухни не указано, что он является квартирой-студией. И хотя такая площадь кухни может быть реальной, всё же в качестве критерия следует установить минимальное значение площади кухни — 2 м². Именно это значение является минимальным, если не учитывать значение 1,3 м². И кухни такой площади встречаются уже в четырёх объектах недвижимости.

In [74]:
columns = ['total_area', 'living_area', 'kitchen_area', 'rooms',
           'studio', 'floors_total', 'locality_name']

data[columns][data['living_area'].notna()].sort_values(by='kitchen_area').head(7)
Out[74]:
total_area living_area kitchen_area rooms studio floors_total locality_name
20217 28.5 19.5 1.3 1 False 14.0 Санкт-Петербург
11033 32.0 16.0 2.0 1 False 14.0 Санкт-Петербург
6262 24.0 16.0 2.0 2 False 5.0 Санкт-Петербург
906 27.0 18.0 2.0 1 False 23.0 Санкт-Петербург
21419 20.0 14.0 2.0 1 False 5.0 Санкт-Петербург
17834 34.7 15.5 2.3 1 False 26.0 Мурино
8729 18.4 14.0 2.4 1 False 3.0 Пушкин

Заменим значение 1,3 м² на 2 м².

In [75]:
data.loc[data['kitchen_area'] < 2, 'kitchen_area'] = 2
len(data.loc[data['kitchen_area'] < 2])
Out[75]:
0

Теперь выясним, есть ли среди записей такие объекты недвижимости, у которых не указана площадь кухни, и разность общей площади и жилой площади меньше 4 м²: 2 м² — минимальное значение площади кухни, и 2 м² — минимальное значение площади вспомогательных помещений (кроме кухни).

In [76]:
data[~data['studio'] &
     (data['rooms'] != 0) &
     ((data['total_area'] - data['living_area']).round(2) < 4)]
Out[76]:
total_images last_price total_area first_day_exposition rooms ceiling_height floors_total living_area floor is_apartment studio open_plan kitchen_area balcony locality_name airports_nearest city_centers_nearest parks_around_3000 parks_nearest ponds_around_3000 ponds_nearest days_exposition locality_type
4339 19 6900000.0 72.0 2019-03-25T00:00:00 3 3.50 4.0 70.0 1 True False False NaN NaN Санкт-Петербург 31487.0 4466.0 2.0 353.0 1.0 439.0 22.0 город
7052 4 2650000.0 23.3 2017-11-25T00:00:00 1 NaN 12.0 20.0 10 NaN False False NaN NaN Санкт-Петербург 20381.0 19383.0 0.0 NaN 1.0 579.0 355.0 город
9157 0 3400000.0 17.6 2018-03-18T00:00:00 1 NaN 5.0 15.0 2 NaN False False NaN NaN Санкт-Петербург 21555.0 1967.0 2.0 336.0 1.0 309.0 117.0 город
19268 10 3450000.0 43.3 2018-09-18T00:00:00 1 2.75 18.0 41.3 7 NaN False False NaN 2.0 Мурино NaN NaN NaN NaN NaN NaN 44.0 посёлок
19807 0 3800000.0 13.0 2018-07-04T00:00:00 1 NaN 5.0 10.0 3 NaN False False NaN NaN Санкт-Петербург 21302.0 1242.0 1.0 592.0 3.0 27.0 9.0 город
19904 4 2400000.0 12.0 2017-07-19T00:00:00 1 2.55 5.0 10.0 2 NaN False False NaN NaN Санкт-Петербург 21314.0 964.0 1.0 886.0 2.0 45.0 200.0 город
22095 6 2194000.0 36.5 2017-09-27T00:00:00 1 NaN 3.0 33.2 3 NaN False False NaN 0.0 Санкт-Петербург 39446.0 18500.0 0.0 NaN 2.0 639.0 36.0 город
23191 3 1900000.0 18.9 2016-04-04T00:00:00 1 NaN 16.0 16.0 12 NaN False False NaN 0.0 Тосно NaN NaN NaN NaN NaN NaN 115.0 город

Поскольку не представляется возможным выяснить, значения каких признаков (общей площади, жилой площади) были заполнены ошибочно, записи с несогласующимися значениями необходимо удалить.

In [77]:
data.drop(index=data[~data['studio'] &
                     (data['rooms'] != 0) &
                     ((data['total_area'] - data['living_area']).round(2) < 4)].index,
          inplace=True)

len(data[~data['studio'] &
         (data['rooms'] != 0) &
         ((data['total_area'] - data['living_area']).round(2) < 4)])
Out[77]:
0

Этажность здания¶

Признак floors_total содержит экстремальные значения: существование в Санкт-Петербурге и Ленинградской области жилых зданий высотой 52 и 60 этажей представляется сомнительными.

In [78]:
data['floors_total'].sort_values(ascending=False).unique()
Out[78]:
array([60., 52., 37., 36., 35., 34., 33., 29., 28., 27., 26., 25., 24.,
       23., 22., 21., 20., 19., 18., 17., 16., 15., 14., 13., 12., 11.,
       10.,  9.,  8.,  7.,  6.,  5.,  4.,  3.,  2.,  1., nan])

Самым высоким жилым зданием Санкт-Петербурга и Ленинградской области является жилой комплекс "Князь Александр Невский". Здание насчитывает 35 надземных этажей (это этажность здания) и 2 подземных этажа. Таким образом, максимальное значение этажности в наборе данных может достигать значения 35. Однако в наборе данных представлены записи, в которых объекты недвижимости расположены в зданиях, имеющих этажность более 35 этажей.

Обзор значений

Выясним, где расположены здания, этажность которых превышает 35 этажей, и сколько таких зданий.

In [79]:
columns = ['ceiling_height', 'floor', 'floors_total', 'locality_name',
           'city_centers_nearest', 'airports_nearest']

data[columns].sort_values('floors_total', ascending=False).head(8)
Out[79]:
ceiling_height floor floors_total locality_name city_centers_nearest airports_nearest
2253 2.88 4 60.0 Кронштадт 49488.0 67763.0
16731 2.65 18 52.0 Санкт-Петербург 12978.0 20728.0
16934 1.75 5 37.0 Санкт-Петербург 20444.0 18732.0
11079 2.70 29 36.0 Санкт-Петербург 20444.0 18732.0
397 NaN 28 36.0 Санкт-Петербург 20444.0 18732.0
5807 27.00 13 36.0 Санкт-Петербург 20444.0 18732.0
18218 NaN 33 35.0 Санкт-Петербург 20450.0 18737.0
12888 2.70 27 35.0 Санкт-Петербург 20444.0 18732.0

В наборе данных имеется шесть записей с аномальными значениями этажности. Здание высотой 60 этажей расположено в Кронштадте, а высотой 52 этажа — в Санкт-Петербурге.

Кроме того, в четырёх записях указана этажность здания 36—37 этажей. Причём на таком же расстоянии от центра Санкт-Петербурга (и от аэропорта тоже) расположено 35-этажное здание. Можно сделать вывод, что все объекты недвижимости расположены в одном здании — ЖК "Князь Александр Невский".

Редактирование значений

Запись № 2253. Найдём расположенные рядом объекты недвижимости.

In [80]:
data[columns][(data['locality_name'] == 'Кронштадт')].sort_values(by='floors_total')
Out[80]:
ceiling_height floor floors_total locality_name city_centers_nearest airports_nearest
15586 2.50 1 2.0 Кронштадт 50329.0 68604.0
2720 4.00 1 2.0 Кронштадт 50067.0 68341.0
72 2.70 2 3.0 Кронштадт 49984.0 68258.0
12846 3.55 2 3.0 Кронштадт 51136.0 69410.0
13995 3.18 1 3.0 Кронштадт 50282.0 68556.0
... ... ... ... ... ... ...
11190 2.51 9 12.0 Кронштадт 47054.0 65328.0
23114 NaN 3 13.0 Кронштадт 46979.0 65254.0
8826 NaN 11 15.0 Кронштадт 46979.0 65254.0
10189 2.51 16 20.0 Кронштадт 49767.0 68042.0
2253 2.88 4 60.0 Кронштадт 49488.0 67763.0

95 rows × 6 columns

Вероятно, в значении этажности положение запятой, отделяющей десятичную часть, сместилось на один знак вправо. Однако в наборе данных не представлены записи об объектах недвижимости в Кронштадте высотой 6 и даже 16 или 26 этажей.
С другой стороны, во всём наборе данных представлено большое количество объектов недвижимости, расположенных на 6 этаже, в которых высота потолков может быть не менее 2,88 м.

In [81]:
data[data['ceiling_height'] >= 2.88]['floors_total'].value_counts().head()
Out[81]:
floors_total
5.0    885
4.0    444
6.0    422
7.0    224
3.0    171
Name: count, dtype: int64

Заменим 60 на 6 в обозначении этажности.

In [82]:
data.loc[data['floors_total'] == 60, 'floors_total'] = 6
data.loc[[2253], columns]
Out[82]:
ceiling_height floor floors_total locality_name city_centers_nearest airports_nearest
2253 2.88 4 6.0 Кронштадт 49488.0 67763.0

Запись № 16731. В наборе данных отсутствуют записи об объектах недвижимости, расположенных на таком же расстоянии от центра Санкт-Петербурга и от аэропорта. Поскольку объект расположен на 18 этаже, и высота потолков составляет 2,65 м, найдём сведения о зданиях высотой не менее 18 этажей с высотой потолков в квартирах не менее 2,65 м.

In [83]:
data.loc[(data['floors_total'] >= 18) &
         (data['ceiling_height'] >= 2.65),
         'floors_total'].value_counts().head()
Out[83]:
floors_total
25.0    447
18.0    196
23.0    178
24.0    178
20.0    142
Name: count, dtype: int64

Наибольшее число зданий, подходящих под выбранный критерий, — это 25-этажные здания. Вероятно, была допущена ошибка при наборе значения количества этажей в здании, и цифры были записаны в обратном порядке. Заменим 52 на 25 в обозначении этажности.

In [84]:
data.loc[data['floors_total'] == 52, 'floors_total'] = 25
data.loc[[16731], columns]
Out[84]:
ceiling_height floor floors_total locality_name city_centers_nearest airports_nearest
16731 2.65 18 25.0 Санкт-Петербург 12978.0 20728.0

В списке уникальных значений признака floors_total можно заметить, что после значения 29 следующее значение идёт 33.
Выясним, на каких расстояниях от центра Санкт-Петербурга и аэропорта расположены здания этажностью более 29 этажей.

In [85]:
data.loc[data['floors_total'] >= 30,
         'city_centers_nearest'].sort_values().unique()
Out[85]:
array([20339., 20444., 20450.])
In [86]:
data.loc[data['floors_total'] >= 30,
         'airports_nearest'].sort_values().unique()
Out[86]:
array([18627., 18732., 18737.])

Все объекты расположены в здании, расположенном в одном месте. Значения расстояний до центра Санкт-Петербурга и до аэропорта различаются незначительно. Это может быть связано с различным способом построения маршрута на Яндекс.Картах, либо напрямую связано с разными дистанциями, преодолеваемыми до разных секций жилого комплекса.

Заменим все значения этажности, превышающие 29, на 35.

In [87]:
data.loc[data['floors_total'] >= 30, 'floors_total'] = 35
In [88]:
data['floors_total'].sort_values(ascending=False).unique()
Out[88]:
array([35., 29., 28., 27., 26., 25., 24., 23., 22., 21., 20., 19., 18.,
       17., 16., 15., 14., 13., 12., 11., 10.,  9.,  8.,  7.,  6.,  5.,
        4.,  3.,  2.,  1., nan])

Этажность зданий не превышает значения 35 — этажности самого высокого жилого здания Санкт-Петербурга и Ленинградской области.

Расстояние до аэропорта¶

Среди всех значений признака airports_nearest одно вызывает наибольшее сомнение. Если бы значение 0 м было правильным, это бы означало, что объект недвижимости расположен в аэропорту, что, конечно же, неправда.

In [89]:
data['airports_nearest'].value_counts().sort_index().head()
Out[89]:
airports_nearest
0.0       1
6450.0    2
6914.0    1
6949.0    1
6989.0    6
Name: count, dtype: int64

Обзор значений

Выясним, где на самом деле расположены объекты, расстояние от которых до аэропорта равно 0 м.

In [90]:
data[columns][data['airports_nearest'] == 0]
Out[90]:
ceiling_height floor floors_total locality_name city_centers_nearest airports_nearest
21085 2.7 3 9.0 Санкт-Петербург 22801.0 0.0

Такой объект один, и расположен он в Санкт-Петербурге. Вероятно, имел место технический сбой, который и привёл к потере значения.

Запись № 21085. Выясним, есть ли поблизости схожие по характеристикам здания.

In [91]:
data[columns][(data['city_centers_nearest'] > 22500) &
              (data['city_centers_nearest'] < 23000) &
              (data['floors_total'] == 9)] \
              .sort_values(by='city_centers_nearest')
Out[91]:
ceiling_height floor floors_total locality_name city_centers_nearest airports_nearest
19440 2.55 1 9.0 Санкт-Петербург 22619.0 20907.0
21085 2.70 3 9.0 Санкт-Петербург 22801.0 0.0
21621 NaN 1 9.0 Санкт-Петербург 22902.0 21190.0

Рядом с 9-этажным зданием расположены другие 9-этажные здания (или секции этого же здания). Легко заметить, что изменение расстояний до центра Санкт-Петербурга и до аэропорта происходят симбатно и изменяются на одну и ту же величину. Тогда наиболее вероятное значение расстояния до аэропорта у объекта будет 21 100 м. Заменим 0 м на 21 100 м.

In [92]:
data.loc[21085, 'airports_nearest'] = 21100
data.loc[[21085], columns]
Out[92]:
ceiling_height floor floors_total locality_name city_centers_nearest airports_nearest
21085 2.7 3 9.0 Санкт-Петербург 22801.0 21100.0
In [93]:
data['airports_nearest'].value_counts().sort_index().head()
Out[93]:
airports_nearest
6450.0    2
6914.0    1
6949.0    1
6989.0    6
6992.0    1
Name: count, dtype: int64

Все объекты недвижимости расположены на удалении от аэропорта. На территории аэропорта объектов жилой недвижимости нет.

Расстояние до ближайшего парка¶

Признак parks_nearest содержит экстремальные значения: превышающие 3 км.

In [94]:
data['parks_nearest'].value_counts().sort_index().tail()
Out[94]:
parks_nearest
2905.0    1
2984.0    1
3013.0    1
3064.0    1
3190.0    2
Name: count, dtype: int64

Значения признака parks_around_3000 указывает на количество ближайших парков в радиусе 3 км от здания, в котором расположен объект недвижимости. Таким образом, значения признаков pakrs_around_3000 и parks_nearest являются связанными. Значения этих признаков должны быть согласованы.

Обзор значений

Выясним, какие записи содержат значение признака parks_nearest, превышающее 3000 м.

In [95]:
columns = ['locality_name', 'parks_around_3000', 'parks_nearest']

data[columns][data['parks_nearest'] >= 3000]
Out[95]:
locality_name parks_around_3000 parks_nearest
1590 Санкт-Петербург 0.0 3064.0
10959 Санкт-Петербург 0.0 3190.0
19208 Санкт-Петербург 0.0 3013.0
19430 Санкт-Петербург 0.0 3190.0

Таких записей всего четыре. Можно заметить, что количество парков в радиусе 3 км равно 0. Этот уровень значений признака parks_around_3000 указан в явном виде.

Редактирование значений

Вероятно, имел место технический сбой, поэтому Яндекс.Карты записали значение расстояния до ближайшего парка, несмотря на то, что оно превышает 3 км. Либо для значений признака parks_nearest установлена высокая предельно допустимая погрешность.

Заменим значения, превышающие 3000 м, на NaN. И убедимся, что все указанные расстояния до ближайшего парка не превышают 3 км.

In [96]:
data.loc[data['parks_nearest'] >= 3000, 'parks_nearest'] = np.nan
len(data[data['parks_nearest'] >= 3000])
Out[96]:
0

Посмотрим на значения расстояний до ближайшего парка, близкие к граничному значению — 3 км.

In [97]:
columns = ['locality_name', 'city_centers_nearest',
           'parks_around_3000', 'parks_nearest']

data[columns].sort_values(by='parks_nearest', ascending=False).head(10)
Out[97]:
locality_name city_centers_nearest parks_around_3000 parks_nearest
23080 Санкт-Петербург 9877.0 1.0 2984.0
2659 Санкт-Петербург 9016.0 1.0 2905.0
1860 Санкт-Петербург 9983.0 1.0 2888.0
7855 Санкт-Петербург 9972.0 1.0 2880.0
3865 Санкт-Петербург 8791.0 1.0 2847.0
22003 Санкт-Петербург 8879.0 1.0 2768.0
7316 Санкт-Петербург 8679.0 2.0 2747.0
5923 Санкт-Петербург 8729.0 1.0 2711.0
1804 Санкт-Петербург 9271.0 2.0 2665.0
6625 Санкт-Петербург 10124.0 1.0 2633.0

Поскольку значение количества ближайших парков равно одному для граничных значений расстояния до ближайшего парка, можно в данном случае заключить, что значения признаков parks_around_3000 и parks_nearest не противоречат друг другу.

Если значения расстояний до ближайшего парка ограничены сверху природой признака parks_around_3000, то для ограничения снизу такого связанного признака нет. Однако значения расстояний должны отвечать здравому смыслу.

В наборе данных наблюдаются записи с подозрительно маленькими расстояниями до ближайшего парка. Маленькое расстояние до парка (порядка нескольких метров) означало бы, что выход из здания, где расположен объект недвижимости, ведёт прямо в парк. Такое расположение парка относительно здания маловероятно. Зачастую необходимо перейти через автомобильную дорогу или хотя бы через асфальтированную пешеходную дорогу, примыкающую непосредственно к зданию.

Обзор значений

Выясним, в скольких записях указано маленькое расстояние от здания до ближайшего парка и где расположены эти здания.

In [98]:
columns = ['floor', 'floors_total', 'locality_name', 'city_centers_nearest',
           'parks_around_3000', 'parks_nearest']

data[columns][data['parks_nearest'] > 0].sort_values(by='parks_nearest').head(20)
Out[98]:
floor floors_total locality_name city_centers_nearest parks_around_3000 parks_nearest
14624 2 9.0 Санкт-Петербург 16436.0 1.0 1.0
11949 7 9.0 Санкт-Петербург 12292.0 1.0 3.0
22941 4 4.0 Зеленогорск 54490.0 3.0 4.0
9344 1 9.0 Санкт-Петербург 11665.0 1.0 7.0
2527 2 5.0 Кронштадт 51500.0 3.0 9.0
20193 3 9.0 Санкт-Петербург 6410.0 2.0 9.0
15296 9 9.0 Санкт-Петербург 12168.0 1.0 10.0
189 5 9.0 Санкт-Петербург 12168.0 1.0 10.0
19093 2 9.0 Санкт-Петербург 12168.0 1.0 10.0
21773 4 9.0 Санкт-Петербург 12168.0 1.0 10.0
4470 3 9.0 Санкт-Петербург 12168.0 1.0 10.0
7788 3 7.0 Санкт-Петербург 10661.0 2.0 10.0
214 8 9.0 Санкт-Петербург 12168.0 1.0 10.0
12018 3 5.0 Санкт-Петербург 7419.0 2.0 11.0
16831 10 12.0 Санкт-Петербург 9555.0 1.0 11.0
21167 3 5.0 Пушкин 33161.0 1.0 11.0
1214 8 9.0 Санкт-Петербург 11564.0 2.0 11.0
19215 6 9.0 Санкт-Петербург 11564.0 2.0 11.0
14015 2 9.0 Пушкин 32456.0 1.0 12.0
22791 2 3.0 Петергоф 30627.0 2.0 13.0

Практически все объекты расположены в Санкт-Петербурге. Расстояние до ближайшего парка, равное нескольким метрам, указано в шести записях. Основная масса значений начинается с 10 м. Поэтому представляется разумным задать в качестве критерия минимальную границу значения расстояния от здания до ближайшего парка — 10 м.

Редактирование значений

В записях, в которых указано расстояние до ближайшего парка менее 10 м, заменим значения расстояний на 10 м.

In [99]:
data.loc[data['parks_nearest'] < 10, 'parks_nearest'] = 10
len(data[(data['parks_nearest'] < 10) & (data['parks_nearest'] > 0)])
Out[99]:
0
In [100]:
data['parks_nearest'].value_counts().sort_index().head()
Out[100]:
parks_nearest
10.0    13
11.0     5
12.0     1
13.0     6
14.0     1
Name: count, dtype: int64
In [101]:
data['parks_nearest'].value_counts().sort_index().tail()
Out[101]:
parks_nearest
2847.0    1
2880.0    1
2888.0    1
2905.0    1
2984.0    1
Name: count, dtype: int64

Все значения расстояния до ближайшего парка лежат в диапазоне от 10 м до 3000 м.

Высота потолков¶

Среди значений высоты потолков можно заметить экстремально большие значения — превышающие 10 м, и аномально низкие значения — не превышающие 1,5 м.

In [102]:
data['ceiling_height'].sort_values(ascending=False).unique()
Out[102]:
array([32.  , 27.  , 26.  , 25.  , 24.  , 22.6 , 20.  , 14.  , 10.3 ,
        8.3 ,  8.  ,  6.  ,  5.8 ,  5.6 ,  5.5 ,  5.3 ,  5.2 ,  5.  ,
        4.9 ,  4.8 ,  4.7 ,  4.65,  4.5 ,  4.45,  4.4 ,  4.37,  4.3 ,
        4.25,  4.2 ,  4.19,  4.15,  4.14,  4.1 ,  4.06,  4.  ,  3.98,
        3.95,  3.93,  3.9 ,  3.88,  3.87,  3.86,  3.85,  3.84,  3.83,
        3.82,  3.8 ,  3.78,  3.76,  3.75,  3.7 ,  3.69,  3.68,  3.67,
        3.66,  3.65,  3.63,  3.62,  3.6 ,  3.59,  3.58,  3.57,  3.56,
        3.55,  3.54,  3.53,  3.52,  3.51,  3.5 ,  3.49,  3.48,  3.47,
        3.46,  3.45,  3.44,  3.43,  3.42,  3.4 ,  3.39,  3.38,  3.37,
        3.36,  3.35,  3.34,  3.33,  3.32,  3.31,  3.3 ,  3.29,  3.28,
        3.27,  3.26,  3.25,  3.24,  3.23,  3.22,  3.21,  3.2 ,  3.18,
        3.17,  3.16,  3.15,  3.14,  3.13,  3.12,  3.11,  3.1 ,  3.09,
        3.08,  3.07,  3.06,  3.05,  3.04,  3.03,  3.02,  3.01,  3.  ,
        2.99,  2.98,  2.97,  2.96,  2.95,  2.94,  2.93,  2.92,  2.91,
        2.9 ,  2.89,  2.88,  2.87,  2.86,  2.85,  2.84,  2.83,  2.82,
        2.81,  2.8 ,  2.79,  2.78,  2.77,  2.76,  2.75,  2.74,  2.73,
        2.72,  2.71,  2.7 ,  2.69,  2.68,  2.67,  2.66,  2.65,  2.64,
        2.63,  2.62,  2.61,  2.6 ,  2.59,  2.58,  2.57,  2.56,  2.55,
        2.54,  2.53,  2.52,  2.51,  2.5 ,  2.49,  2.48,  2.47,  2.46,
        2.45,  2.4 ,  2.34,  2.3 ,  2.25,  2.  ,  1.75,  1.2 ,  1.  ,
         nan])

Редактирование значений

Вероятно, в значениях 20—32 м положение запятой, отделяющей десятичную часть, сместилось на один знак вправо. Уменьшим эти значения в 10 раз.

In [103]:
data.loc[data['ceiling_height'] >= 20, 'ceiling_height'] = data['ceiling_height'] / 10
data['ceiling_height'].sort_values(ascending=False).unique()
Out[103]:
array([14.  , 10.3 ,  8.3 ,  8.  ,  6.  ,  5.8 ,  5.6 ,  5.5 ,  5.3 ,
        5.2 ,  5.  ,  4.9 ,  4.8 ,  4.7 ,  4.65,  4.5 ,  4.45,  4.4 ,
        4.37,  4.3 ,  4.25,  4.2 ,  4.19,  4.15,  4.14,  4.1 ,  4.06,
        4.  ,  3.98,  3.95,  3.93,  3.9 ,  3.88,  3.87,  3.86,  3.85,
        3.84,  3.83,  3.82,  3.8 ,  3.78,  3.76,  3.75,  3.7 ,  3.69,
        3.68,  3.67,  3.66,  3.65,  3.63,  3.62,  3.6 ,  3.59,  3.58,
        3.57,  3.56,  3.55,  3.54,  3.53,  3.52,  3.51,  3.5 ,  3.49,
        3.48,  3.47,  3.46,  3.45,  3.44,  3.43,  3.42,  3.4 ,  3.39,
        3.38,  3.37,  3.36,  3.35,  3.34,  3.33,  3.32,  3.31,  3.3 ,
        3.29,  3.28,  3.27,  3.26,  3.25,  3.24,  3.23,  3.22,  3.21,
        3.2 ,  3.18,  3.17,  3.16,  3.15,  3.14,  3.13,  3.12,  3.11,
        3.1 ,  3.09,  3.08,  3.07,  3.06,  3.05,  3.04,  3.03,  3.02,
        3.01,  3.  ,  2.99,  2.98,  2.97,  2.96,  2.95,  2.94,  2.93,
        2.92,  2.91,  2.9 ,  2.89,  2.88,  2.87,  2.86,  2.85,  2.84,
        2.83,  2.82,  2.81,  2.8 ,  2.79,  2.78,  2.77,  2.76,  2.75,
        2.74,  2.73,  2.72,  2.71,  2.7 ,  2.69,  2.68,  2.67,  2.66,
        2.65,  2.64,  2.63,  2.62,  2.61,  2.6 ,  2.59,  2.58,  2.57,
        2.56,  2.55,  2.54,  2.53,  2.52,  2.51,  2.5 ,  2.49,  2.48,
        2.47,  2.46,  2.45,  2.4 ,  2.34,  2.3 ,  2.26,  2.25,  2.  ,
        1.75,  1.2 ,  1.  ,   nan])

Запись № 15061. Объект недвижимости расположен на 5 этаже 14-этажного здания. Высота потолков 14 м является ошибочным значением.

In [104]:
columns = ['ceiling_height', 'floor', 'floors_total', 'locality_name',
           'city_centers_nearest', 'airports_nearest']

data[columns][data['ceiling_height'] == 14]
Out[104]:
ceiling_height floor floors_total locality_name city_centers_nearest airports_nearest
15061 14.0 5 14.0 Санкт-Петербург 13610.0 14814.0

Найдём объекты недвижимости, расположенные поблизости и имеющие схожие характеристики.

In [105]:
data[columns][(data['ceiling_height'].notna()) &
              (data['locality_name'] == 'Санкт-Петербург') &
              (data['city_centers_nearest'] > 13600) &
              (data['city_centers_nearest'] < 13620) &
              (data['airports_nearest'] > 14800) &
              (data['airports_nearest'] < 14830)].sort_values('ceiling_height')
Out[105]:
ceiling_height floor floors_total locality_name city_centers_nearest airports_nearest
2050 2.6 8 12.0 Санкт-Петербург 13606.0 14809.0
2524 2.7 1 12.0 Санкт-Петербург 13606.0 14809.0
8748 2.7 6 16.0 Санкт-Петербург 13606.0 14809.0
11610 2.7 16 16.0 Санкт-Петербург 13606.0 14809.0
15058 2.7 5 16.0 Санкт-Петербург 13606.0 14809.0
15515 2.7 13 16.0 Санкт-Петербург 13606.0 14809.0
16299 2.7 7 16.0 Санкт-Петербург 13606.0 14809.0
19243 2.7 7 16.0 Санкт-Петербург 13606.0 14809.0
20774 2.7 1 16.0 Санкт-Петербург 13606.0 14809.0
21678 2.7 8 10.0 Санкт-Петербург 13607.0 14811.0
22579 2.7 1 16.0 Санкт-Петербург 13606.0 14809.0
15061 14.0 5 14.0 Санкт-Петербург 13610.0 14814.0

Найденные объекты недвижимости преимущественно имеют высоту потолков равную 2,7 м. Заменим значение высоты потолка 14 м на 2,7 м.

In [106]:
data.loc[data['ceiling_height'] == 14, 'ceiling_height'] = 2.7
data.loc[[15061], columns]
Out[106]:
ceiling_height floor floors_total locality_name city_centers_nearest airports_nearest
15061 2.7 5 14.0 Санкт-Петербург 13610.0 14814.0

Запись № 22309. Объект недвижимости расположен на 15 этаже 16-этажного здания. Высота потолков 10,3 м является ошибочным значением.

In [107]:
data[columns][data['ceiling_height'] == 10.3]
Out[107]:
ceiling_height floor floors_total locality_name city_centers_nearest airports_nearest
22309 10.3 15 16.0 Санкт-Петербург 11936.0 36353.0

Найдём объекты недвижимости, расположенные поблизости и имеющие схожие характеристики.

In [108]:
data[columns][(data['ceiling_height'].notna()) &
              (data['city_centers_nearest'] == 11936) &
              (data['airports_nearest'] == 36353)].sort_values('ceiling_height')
Out[108]:
ceiling_height floor floors_total locality_name city_centers_nearest airports_nearest
16892 2.50 13 15.0 Санкт-Петербург 11936.0 36353.0
19531 2.75 2 16.0 Санкт-Петербург 11936.0 36353.0
1207 2.77 12 16.0 Санкт-Петербург 11936.0 36353.0
10772 2.80 7 16.0 Санкт-Петербург 11936.0 36353.0
12770 2.80 4 16.0 Санкт-Петербург 11936.0 36353.0
22309 10.30 15 16.0 Санкт-Петербург 11936.0 36353.0

Найденные объекты недвижимости имеют высоту потолков в интервале 2,5—2,8 м. Такой разброс значений может быть связан с уменьшением высоты потолка после установки натяжного потолка или монтажа многоуровневой потолочной системы. Заменим значение высоты потолка 10,3 м на среднее арифметическое значение — 2,7 м.

In [109]:
data.loc[data['ceiling_height'] == 10.3, 'ceiling_height'] = 2.7
data.loc[[22309], columns]
Out[109]:
ceiling_height floor floors_total locality_name city_centers_nearest airports_nearest
22309 2.7 15 16.0 Санкт-Петербург 11936.0 36353.0

Запись № 5863. Объект недвижимости расположен на 14 этаже 16-этажного здания. Высота потолков 8,3 м является ошибочным значением.

In [110]:
data[columns][data['ceiling_height'] == 8.3]
Out[110]:
ceiling_height floor floors_total locality_name city_centers_nearest airports_nearest
5863 8.3 14 16.0 Санкт-Петербург 10763.0 13069.0

Поскольку не представляется возможным найти похожие по характеристикам объекты недвижимости, узнаем медианное значение высоты потолков 16-этажных зданий, расположенных в Санкт-Петербурге.

In [111]:
data[columns][(data['ceiling_height'].notna()) &
              (data['locality_name'] == 'Санкт-Петербург') &
              (data['floors_total'] == 16)]['ceiling_height'].median()
Out[111]:
2.7

Медианное значение составляет 2,7 м. Заменим значение высоты потолка 8,3 м на 2,7 м.

In [112]:
data.loc[data['ceiling_height'] == 8.3, 'ceiling_height'] = 2.7
data.loc[[5863], columns]
Out[112]:
ceiling_height floor floors_total locality_name city_centers_nearest airports_nearest
5863 2.7 14 16.0 Санкт-Петербург 10763.0 13069.0

Высота потолков равная 8 м указана сразу в трёх записях. Все объекты недвижимости расположены в разных населённых пунктах на 1 или 2 этажах зданий.

In [113]:
data[columns][data['ceiling_height'] == 8]
Out[113]:
ceiling_height floor floors_total locality_name city_centers_nearest airports_nearest
3474 8.0 2 5.0 Нурма NaN NaN
15743 8.0 1 16.0 Санкт-Петербург 11035.0 32691.0
17442 8.0 2 5.0 Красное Село 28062.0 24638.0

Запись № 15743. Объект недвижимости расположен на 1 этаже 16-этажного здания в Санкт-Петербурге. Найдём похожие по характеристикам объекты недвижимости.

In [114]:
data[columns][(data['ceiling_height'].notna()) &
              (data['city_centers_nearest'] == 11035) &
              (data['airports_nearest'] == 32691)].sort_values('ceiling_height')
Out[114]:
ceiling_height floor floors_total locality_name city_centers_nearest airports_nearest
22271 2.5 4 15.0 Санкт-Петербург 11035.0 32691.0
15743 8.0 1 16.0 Санкт-Петербург 11035.0 32691.0

Схожий по характеристикам объект недвижимости имеет высоту потолков 2,5 м. Заменим значение высоты потолка 8 м на 2,5 м.

In [115]:
data.loc[15743, 'ceiling_height'] = 2.5
data.loc[[15743], columns]
Out[115]:
ceiling_height floor floors_total locality_name city_centers_nearest airports_nearest
15743 2.5 1 16.0 Санкт-Петербург 11035.0 32691.0

Запись № 17442. Объект недвижимости расположен на 2 этаже 5-этажного здания в Красном Селе. Найдём похожие по характеристикам объекты недвижимости.

In [116]:
data[columns][(data['ceiling_height'].notna()) &
              (data['city_centers_nearest'] == 28062) &
              (data['airports_nearest'] == 24638)].sort_values('ceiling_height')
Out[116]:
ceiling_height floor floors_total locality_name city_centers_nearest airports_nearest
10392 2.75 3 5.0 Красное Село 28062.0 24638.0
17442 8.00 2 5.0 Красное Село 28062.0 24638.0

Схожий по характеристикам объект недвижимости имеет высоту потолков 2,75 м. Заменим значение высоты потолка 8 м на 2,75 м.

In [117]:
data.loc[17442, 'ceiling_height'] = 2.75
data.loc[[17442], columns]
Out[117]:
ceiling_height floor floors_total locality_name city_centers_nearest airports_nearest
17442 2.75 2 5.0 Красное Село 28062.0 24638.0

Запись № 3474. Объект недвижимости расположен на 2 этаже 5-этажного здания в Нурме. Найдём похожие по характеристикам объекты недвижимости.

In [118]:
data[columns][(data['ceiling_height'].notna()) &
              (data['locality_name'] == 'Нурма') &
              (data['floors_total'] == 5)].sort_values('ceiling_height')
Out[118]:
ceiling_height floor floors_total locality_name city_centers_nearest airports_nearest
596 2.5 3 5.0 Нурма NaN NaN
1570 2.5 5 5.0 Нурма NaN NaN
3917 2.5 5 5.0 Нурма NaN NaN
4599 2.5 5 5.0 Нурма NaN NaN
11842 2.5 5 5.0 Нурма NaN NaN
21376 2.5 4 5.0 Нурма NaN NaN
18916 2.6 1 5.0 Нурма NaN NaN
3474 8.0 2 5.0 Нурма NaN NaN

Схожие по характеристикам объекты недвижимости имеют высоту потолков 2,5 м. Заменим значение высоты потолка 8 м на 2,5 м.

In [119]:
data.loc[3474, 'ceiling_height'] = 2.5
data.loc[[3474], columns]
Out[119]:
ceiling_height floor floors_total locality_name city_centers_nearest airports_nearest
3474 2.5 2 5.0 Нурма NaN NaN
In [120]:
data[columns].sort_values(by='ceiling_height', ascending=False).head(10)
Out[120]:
ceiling_height floor floors_total locality_name city_centers_nearest airports_nearest
20264 6.0 7 7.0 Санкт-Петербург 5605.0 26902.0
21227 5.8 5 5.0 Санкт-Петербург 1261.0 20170.0
1388 5.6 6 6.0 Санкт-Петербург 6934.0 26204.0
7578 5.5 5 5.0 Санкт-Петербург 6448.0 26333.0
1026 5.3 3 3.0 Санкт-Петербург 4785.0 24899.0
12628 5.3 5 5.0 Санкт-Петербург 3918.0 19644.0
464 5.2 7 8.0 Санкт-Петербург 6655.0 26316.0
1053 5.0 1 3.0 Бокситогорск NaN NaN
21923 4.9 5 5.0 Санкт-Петербург 1328.0 22777.0
2802 4.8 2 3.0 Санкт-Петербург 1725.0 24433.0

Значение высоты потолка равное 6 м и менее является допустимым, поскольку объекты недвижимости с высокими потолками располагаются на последних этажах зданий и зачастую имеют большую площадь. Это позволяет предполагать, что данные объекты недвижимости являются пентхаусом.

Поскольку в определении этажа есть указание, что это "пространство высотой в чистоте (от пола до потолка) 1,8 м и более", и если ещё учитывать средний рост человека, то логично предположить, что значения высоты потолков менее 1,8 м является также ошибочными.

Запись № 22590. Объект недвижимости расположен на 7 этаже 12-этажного здания. Значение высоты потолков 1 м является ошибочным.

In [121]:
data[columns][data['ceiling_height'] == 1]
Out[121]:
ceiling_height floor floors_total locality_name city_centers_nearest airports_nearest
22590 1.0 7 12.0 Санкт-Петербург 14217.0 33053.0

Найдём схожие по характеристикам объекты недвижимости.

In [122]:
data[columns][(data['ceiling_height'].notna()) &
              (data['city_centers_nearest'] == 14217) &
              (data['airports_nearest'] == 33053)]
Out[122]:
ceiling_height floor floors_total locality_name city_centers_nearest airports_nearest
15420 2.7 2 12.0 Санкт-Петербург 14217.0 33053.0
22590 1.0 7 12.0 Санкт-Петербург 14217.0 33053.0

Схожий объект недвижимости имеет высоту потолка 2,7 м. Заменим значение высоты потолка 1 м на 2,7 м.

In [123]:
data.loc[22590, 'ceiling_height'] = 2.7
data.loc[[22590], columns]
Out[123]:
ceiling_height floor floors_total locality_name city_centers_nearest airports_nearest
22590 2.7 7 12.0 Санкт-Петербург 14217.0 33053.0

Запись № 5172. Объект недвижимости расположен на 1 этаже 2-этажного здания. Значение высоты потолков 1,2 м является ошибочным.

In [124]:
data[columns][data['ceiling_height'] == 1.2]
Out[124]:
ceiling_height floor floors_total locality_name city_centers_nearest airports_nearest
5712 1.2 1 2.0 Мга NaN NaN

Найдём схожие по характеристикам объекты недвижимости.

In [125]:
data[columns][(data['ceiling_height'].notna()) &
              (data['locality_name'] == 'Мга') &
              (data['floors_total'] == 2)]
Out[125]:
ceiling_height floor floors_total locality_name city_centers_nearest airports_nearest
5712 1.2 1 2.0 Мга NaN NaN
6148 2.5 1 2.0 Мга NaN NaN
7733 2.6 2 2.0 Мга NaN NaN
18636 3.2 2 2.0 Мга NaN NaN
18858 2.6 2 2.0 Мга NaN NaN

Схожими по характеристикам являются несколько объектов недвижимости. Значение высоты потолков у них находится в диапазоне 2,5—3,2 м. Медианное значение равно 2,6 м. Заменим значение высоты потолка 1,2 м на медианное значение 2,6 м.

In [126]:
data.loc[5712, 'ceiling_height'] = 2.6
data.loc[[5712], columns]
Out[126]:
ceiling_height floor floors_total locality_name city_centers_nearest airports_nearest
5712 2.6 1 2.0 Мга NaN NaN

Запись № 16934. Объект недвижимости расположен на 5 этаже 35-этажного здания жилого комплекса "Князь Александр Невский". И хотя значение высоты потолка 1,75 м является близким по значению к 1,8 м, всё же для квартиры в новостройке оно представляется сомнительным.

In [127]:
data[columns][data['ceiling_height'] == 1.75]
Out[127]:
ceiling_height floor floors_total locality_name city_centers_nearest airports_nearest
16934 1.75 5 35.0 Санкт-Петербург 20444.0 18732.0

Выясним, какой высоты потолки в ЖК "Князь Александр Невский".

In [128]:
data[columns][data['ceiling_height'].notna() &
              (data['floors_total'] == 35)]
Out[128]:
ceiling_height floor floors_total locality_name city_centers_nearest airports_nearest
1697 2.65 23 35.0 Санкт-Петербург 20444.0 18732.0
1917 2.80 30 35.0 Санкт-Петербург 20444.0 18732.0
4855 2.80 4 35.0 Санкт-Петербург 20339.0 18627.0
5749 2.80 26 35.0 Санкт-Петербург 20444.0 18732.0
5807 2.70 13 35.0 Санкт-Петербург 20444.0 18732.0
9186 2.50 3 35.0 Санкт-Петербург 20444.0 18732.0
9370 2.70 3 35.0 Санкт-Петербург 20444.0 18732.0
9579 2.68 17 35.0 Санкт-Петербург 20444.0 18732.0
11079 2.70 29 35.0 Санкт-Петербург 20444.0 18732.0
12888 2.70 27 35.0 Санкт-Петербург 20444.0 18732.0
12960 2.70 13 35.0 Санкт-Петербург 20444.0 18732.0
16934 1.75 5 35.0 Санкт-Петербург 20444.0 18732.0
In [129]:
data[data['floors_total'] == 35]['ceiling_height'].median()
Out[129]:
2.7

Высота потолков в ЖК "Князь Александр Невский" изменяется в диапазоне 2,5—2,8 м. Медианное значение — 2,7 м. Однако, вероятнее всего, была допущена ошибка при вводе значения высоты потолка: вместо цифры 2 была указана цифра 1. Поэтому заменим значение высоты потолка 1,75 м на 2,75 м.

In [130]:
data.loc[data['ceiling_height'] == 1.75, 'ceiling_height'] = 2.75
data.loc[[16934], columns]
Out[130]:
ceiling_height floor floors_total locality_name city_centers_nearest airports_nearest
16934 2.75 5 35.0 Санкт-Петербург 20444.0 18732.0
In [131]:
data['ceiling_height'].sort_values(ascending=False).unique()
Out[131]:
array([6.  , 5.8 , 5.6 , 5.5 , 5.3 , 5.2 , 5.  , 4.9 , 4.8 , 4.7 , 4.65,
       4.5 , 4.45, 4.4 , 4.37, 4.3 , 4.25, 4.2 , 4.19, 4.15, 4.14, 4.1 ,
       4.06, 4.  , 3.98, 3.95, 3.93, 3.9 , 3.88, 3.87, 3.86, 3.85, 3.84,
       3.83, 3.82, 3.8 , 3.78, 3.76, 3.75, 3.7 , 3.69, 3.68, 3.67, 3.66,
       3.65, 3.63, 3.62, 3.6 , 3.59, 3.58, 3.57, 3.56, 3.55, 3.54, 3.53,
       3.52, 3.51, 3.5 , 3.49, 3.48, 3.47, 3.46, 3.45, 3.44, 3.43, 3.42,
       3.4 , 3.39, 3.38, 3.37, 3.36, 3.35, 3.34, 3.33, 3.32, 3.31, 3.3 ,
       3.29, 3.28, 3.27, 3.26, 3.25, 3.24, 3.23, 3.22, 3.21, 3.2 , 3.18,
       3.17, 3.16, 3.15, 3.14, 3.13, 3.12, 3.11, 3.1 , 3.09, 3.08, 3.07,
       3.06, 3.05, 3.04, 3.03, 3.02, 3.01, 3.  , 2.99, 2.98, 2.97, 2.96,
       2.95, 2.94, 2.93, 2.92, 2.91, 2.9 , 2.89, 2.88, 2.87, 2.86, 2.85,
       2.84, 2.83, 2.82, 2.81, 2.8 , 2.79, 2.78, 2.77, 2.76, 2.75, 2.74,
       2.73, 2.72, 2.71, 2.7 , 2.69, 2.68, 2.67, 2.66, 2.65, 2.64, 2.63,
       2.62, 2.61, 2.6 , 2.59, 2.58, 2.57, 2.56, 2.55, 2.54, 2.53, 2.52,
       2.51, 2.5 , 2.49, 2.48, 2.47, 2.46, 2.45, 2.4 , 2.34, 2.3 , 2.26,
       2.25, 2.  ,  nan])

Значения высоты потолков во всех объектах недвижимости находятся в диапазоне 2—6 м.

Количество комнат¶

Признак rooms измеряется в порядковой шкале. Значения признака — это уровни, характеризующие объект недвижимости и напрямую связанные с количеством имеющихся жилых комнат (размеченных на плане помещения, либо физически разграниченных стенами внутри помещения). Шкала состоит из ряда натуральных чисел. Шкала не имеет значения ноль, поскольку это значение физически не достижимо (в жилом помещении должна быть хотя бы одна жилая комната).

In [132]:
data['rooms'].sort_values().unique()
Out[132]:
array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 14, 15, 16, 19],
      dtype=int64)

Ноль в значении признака rooms может быть меткой того, что объектом недвижимости является квартира-студия.

In [133]:
data[data['studio']]['rooms'].value_counts()
Out[133]:
rooms
0    138
1     11
Name: count, dtype: int64

Действительно, из 149 записей, в которых отмечено, что объект недвижимости является квартирой-студией, в 138 указано, что количество комнат равно нулю. Однако в 11 записях указано количество комнат равное одному. В законе нет понятия "квартира-студия", поэтому все квартиры-студии должны иметь, по крайней мере, одну жилую комнату. С этой точки зрения, 11 записей были сделаны верно.

In [134]:
data[data['studio'] & (data['rooms'] == 1)]['total_area'].sort_values().unique()
Out[134]:
array([22.  , 23.4 , 25.41, 26.  , 27.  , 28.  , 30.  , 31.  , 32.5 ,
       34.  ])

Зачастую квартирами-студиями называют небольшие по площади однокомнатные квартиры, в которых под кухню выделена зона внутри жилого помещения. Так, общая площадь объектов недвижимости в 11 записях варьируется в диапазоне 22—34 м².

In [135]:
data[data['studio'] & (data['rooms'] == 0)]['total_area'].sort_values().unique()
Out[135]:
array([15.5 , 17.  , 18.  , 18.8 , 19.  , 19.5 , 20.  , 20.5 , 21.  ,
       21.3 , 21.4 , 22.  , 22.2 , 22.3 , 22.7 , 23.  , 23.3 , 23.39,
       23.4 , 23.5 , 23.6 , 23.7 , 23.8 , 24.  , 24.05, 24.1 , 24.2 ,
       24.4 , 24.5 , 24.6 , 24.75, 24.8 , 24.9 , 25.  , 25.3 , 25.4 ,
       25.7 , 26.  , 26.05, 26.23, 26.49, 26.7 , 26.8 , 27.  , 27.11,
       27.3 , 27.4 , 27.55, 27.56, 27.6 , 27.7 , 27.81, 28.  , 28.16,
       28.2 , 28.4 , 28.9 , 29.  , 29.1 , 29.2 , 29.3 , 30.  , 30.1 ,
       30.3 , 31.  , 32.  , 32.03, 32.2 , 32.4 , 32.5 , 32.8 , 38.3 ,
       42.1 , 43.3 , 44.2 , 58.4 , 71.  , 73.6 , 98.4 ])

В большинстве из 138 записей общая площадь помещения не превышает 40 м². Это даёт основание полагать, что указанные в записях объекты недвижимости — 1-комнатные квартиры с планировкой квартиры-студии.

In [136]:
data[data['open_plan']]['rooms'].value_counts()
Out[136]:
rooms
0    56
1     3
3     2
2     1
5     1
4     1
Name: count, dtype: int64

Среди 67 объектов недвижимости со свободной планировкой для 59 указано количество комнат равное нулю. Это позволяет предполагать, что эти объекты недвижимости тоже являются квартирами-студиями.

В понятиях "квартира-студия" и "свободная планировка" заложен один смысл — это отсутствие в помещении разграничивающих комнаты перегородок. По смыслу, понятия являются синонимами. Таким образом, для помещения без внутренних перегородок можно указывать количество комнат, равное одному, поскольку вся жилая площадь представляет собой одну жилую комнату, либо указывать несколько комнат в соответствии с планом помещения.

In [137]:
data[data['open_plan']]['studio'].value_counts()
Out[137]:
studio
False    64
Name: count, dtype: int64
In [138]:
data[data['studio']]['open_plan'].value_counts()
Out[138]:
open_plan
False    149
Name: count, dtype: int64

И хотя ни для одного объекта недвижимости со свободной планировкой не указано, что он является квартирой-студией, и ни для одной квартиры-студии не указано, что это помещение со свободной планировкой, по сути, это понятия одной природы. Возможно, это следствие правила Яндекс.Недвижимости, что при указании одного признака другой не указывается. По факту, значения признаков должны дублировать друг друга. Кроме того, отсутствие законодательных норм в отношении данных понятий не позволяет говорить об их отличии друг от друга.

Редактирование значений

Обратим внимание, что общая площадь 1-комнатных квартир со свободной планировкой не превышает 45 м².

In [139]:
columns = ['total_area', 'rooms', 'floor', 'floors_total',
           'studio', 'open_plan', 'locality_name']

data[columns][data['open_plan'] & (data['rooms'] == 1)]
Out[139]:
total_area rooms floor floors_total studio open_plan locality_name
1379 44.2 1 23 25.0 False True Санкт-Петербург
5668 36.7 1 2 16.0 False True Кудрово
9063 39.0 1 1 17.0 False True Санкт-Петербург

Тогда будем считать, что все квартиры-студии с общей площадью менее 45 м², для которых указано количество комнат равное нулю, являются однокомнатными.

In [140]:
data.loc[data['studio'] &
         (data['rooms'] == 0) &
         (data['total_area'] < 45), 'rooms'] = 1

data[data['studio'] & (data['rooms'] == 1)]['total_area'].sort_values().unique()
Out[140]:
array([15.5 , 17.  , 18.  , 18.8 , 19.  , 19.5 , 20.  , 20.5 , 21.  ,
       21.3 , 21.4 , 22.  , 22.2 , 22.3 , 22.7 , 23.  , 23.3 , 23.39,
       23.4 , 23.5 , 23.6 , 23.7 , 23.8 , 24.  , 24.05, 24.1 , 24.2 ,
       24.4 , 24.5 , 24.6 , 24.75, 24.8 , 24.9 , 25.  , 25.3 , 25.4 ,
       25.41, 25.7 , 26.  , 26.05, 26.23, 26.49, 26.7 , 26.8 , 27.  ,
       27.11, 27.3 , 27.4 , 27.55, 27.56, 27.6 , 27.7 , 27.81, 28.  ,
       28.16, 28.2 , 28.4 , 28.9 , 29.  , 29.1 , 29.2 , 29.3 , 30.  ,
       30.1 , 30.3 , 31.  , 32.  , 32.03, 32.2 , 32.4 , 32.5 , 32.8 ,
       34.  , 38.3 , 42.1 , 43.3 , 44.2 ])

Кроме того, будем считать, что все квартиры со свободной планировкой, у которых общая площадь менее 45 м², для которых указано количество комнат равное нулю, также являются однокомнатными.

In [141]:
data.loc[data['open_plan'] &
         (data['rooms'] == 0) &
         (data['total_area'] < 45), 'rooms'] = 1

data[data['open_plan'] & (data['rooms'] == 1)]['total_area'].sort_values().unique()
Out[141]:
array([16.  , 20.  , 21.  , 22.  , 22.5 , 23.  , 23.06, 23.98, 24.  ,
       25.  , 25.2 , 25.41, 25.9 , 26.  , 26.1 , 26.8 , 27.  , 27.1 ,
       27.3 , 27.32, 27.5 , 27.7 , 28.  , 28.01, 28.05, 28.2 , 28.3 ,
       28.5 , 29.  , 30.  , 30.5 , 31.  , 31.1 , 32.3 , 34.  , 34.4 ,
       35.  , 36.7 , 39.  , 42.63, 44.2 ])

Изучим, для квартир-студий с какой общей площадью указано количество комнат равное нулю.

In [142]:
data[data['studio'] & (data['rooms'] == 0)]
Out[142]:
total_images last_price total_area first_day_exposition rooms ceiling_height floors_total living_area floor is_apartment studio open_plan kitchen_area balcony locality_name airports_nearest city_centers_nearest parks_around_3000 parks_nearest ponds_around_3000 ponds_nearest days_exposition locality_type
3458 6 7400000.0 73.6 2017-05-18T00:00:00 0 NaN 3.0 50.0 1 NaN True False NaN 0.0 Санкт-Петербург 26581.0 6085.0 0.0 NaN 1.0 348.0 60.0 город
13613 16 8100000.0 58.4 2019-04-26T00:00:00 0 3.3 7.0 33.0 6 NaN True False NaN NaN Санкт-Петербург 14509.0 8288.0 0.0 NaN 0.0 NaN NaN город
20082 10 16300000.0 98.4 2017-11-08T00:00:00 0 3.1 5.0 60.5 2 NaN True False NaN NaN Санкт-Петербург 26972.0 5819.0 0.0 NaN 1.0 674.0 537.0 город
21227 0 8200000.0 71.0 2017-07-21T00:00:00 0 5.8 5.0 68.0 5 NaN True False NaN 0.0 Санкт-Петербург 20170.0 1261.0 2.0 295.0 3.0 366.0 30.0 город

Изучим объекты со свободной планировкой и общим количеством комнат больше 1.

In [143]:
data[data['open_plan'] &
     (data['rooms'] > 1)].sort_values(by=['rooms', 'total_area'])
Out[143]:
total_images last_price total_area first_day_exposition rooms ceiling_height floors_total living_area floor is_apartment studio open_plan kitchen_area balcony locality_name airports_nearest city_centers_nearest parks_around_3000 parks_nearest ponds_around_3000 ponds_nearest days_exposition locality_type
12760 0 3350000.0 51.0 2015-01-22T00:00:00 2 2.50 12.0 30.0 10 NaN False True NaN 2.0 Коммунар NaN NaN NaN NaN NaN NaN 521.0 город
14017 13 3990000.0 59.0 2016-03-29T00:00:00 3 2.50 9.0 37.6 3 False False True NaN 1.0 Колпино 27820.0 33606.0 0.0 NaN 1.0 705.0 81.0 город
8861 13 5500000.0 64.5 2015-11-13T00:00:00 3 3.00 5.0 48.0 2 False False True NaN 0.0 Санкт-Петербург 20040.0 2621.0 2.0 205.0 2.0 204.0 229.0 город
19796 1 12000000.0 97.2 2016-04-05T00:00:00 4 3.35 5.0 71.3 2 False False True NaN 0.0 Санкт-Петербург 24559.0 4811.0 0.0 NaN 0.0 NaN 89.0 город
17783 3 48763000.0 157.0 2016-04-01T00:00:00 5 NaN 11.0 NaN 5 NaN False True NaN 0.0 Санкт-Петербург 28399.0 7101.0 2.0 290.0 3.0 221.0 90.0 город

Среди объектов недвижимости со свободной планировкой есть объекты 2-комнатные — с общей площадью менее 59 м², 3-комнатные — с общей площадью менее 97 м², 4-комнатные — с общей площадью менее 157 м². Следуя этому соотношению между общей площадью и количеством комнат, исправим все нулевые значения признака rooms в записях, относящихся к квартирам-студиям.

In [144]:
data.loc[data['studio'] & (data['rooms'] == 0) &
         (data['total_area'] < 59), 'rooms'] = 2
data.loc[data['studio'] & (data['rooms'] == 0) &
         (data['total_area'] < 97), 'rooms'] = 3
data.loc[data['studio'] & (data['rooms'] == 0) &
         (data['total_area'] < 157), 'rooms'] = 4
data[data['studio']]['rooms'].value_counts()
Out[144]:
rooms
1    145
3      2
2      1
4      1
Name: count, dtype: int64

Изучим, для квартир со свободной планировкой с какой общей площадью указано количество комнат равное нулю.

In [145]:
data[data['open_plan'] & (data['rooms'] == 0)]
Out[145]:
total_images last_price total_area first_day_exposition rooms ceiling_height floors_total living_area floor is_apartment studio open_plan kitchen_area balcony locality_name airports_nearest city_centers_nearest parks_around_3000 parks_nearest ponds_around_3000 ponds_nearest days_exposition locality_type
19392 5 71000000.0 371.0 2018-07-26T00:00:00 0 3.57 7.0 NaN 6 NaN False True NaN NaN Санкт-Петербург 25257.0 6060.0 1.0 761.0 1.0 584.0 90.0 город

Среди всех объектов недвижимости, представленных в наборе данных, объекты недвижимости с такой же общей площадью имеют преимущественно 7 комнат.

In [146]:
data[(data['total_area'] > 360) &
     (data['total_area'] < 380)]['rooms'].value_counts()
Out[146]:
rooms
7     4
14    1
3     1
19    1
0     1
5     1
8     1
Name: count, dtype: int64

Заменим нулевое значение признака rooms в записях, относящихся к квартирам со свободной планировкой.

In [147]:
data.loc[data['open_plan'] & (data['rooms'] == 0), 'rooms'] = 7
data[data['open_plan']]['rooms'].value_counts()
Out[147]:
rooms
1    58
3     2
2     1
5     1
7     1
4     1
Name: count, dtype: int64
In [148]:
data['rooms'].sort_values().unique()
Out[148]:
array([ 1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 14, 15, 16, 19],
      dtype=int64)

Продублируем значения True в признаках studio и open_plan.

In [149]:
data.loc[data['studio'], 'open_plan'] = True
data.loc[data['open_plan'], 'studio'] = True
In [150]:
(data['studio'] != data['open_plan']).sum()
Out[150]:
0

Все значения признаков studio и open_plan совпадают. Признак rooms не содержит нулевых значений.

Обработка пропусков¶

In [151]:
def show_na():
    '''
    Функция подсчёта пропущенных значений.

    Возвращает таблицу распределения пропущенных значений,
    отсортированную по убыванию значений.

    '''

    total = data.isna().sum().sort_values(ascending=False)
    percent = (data.isna().sum() /
               data.isna().count() * 100).round(1).sort_values(ascending=False)
    display(pd.concat([total, percent], axis=1, keys=['Всего пропусков', '%']))
In [152]:
show_na()
Всего пропусков %
is_apartment 20740 88.3
parks_nearest 15463 65.9
ponds_nearest 14435 61.5
balcony 11413 48.6
ceiling_height 9107 38.8
airports_nearest 5463 23.3
city_centers_nearest 5440 23.2
ponds_around_3000 5439 23.2
parks_around_3000 5439 23.2
days_exposition 3155 13.4
kitchen_area 2263 9.6
living_area 1903 8.1
floors_total 86 0.4
locality_type 49 0.2
locality_name 49 0.2
total_images 0 0.0
last_price 0 0.0
studio 0 0.0
floor 0 0.0
rooms 0 0.0
first_day_exposition 0 0.0
total_area 0 0.0
open_plan 0 0.0

Сведения об апартаментах¶

Признак is_apartment измеряется в бинарной шкале и может иметь всего два значения: False и True. В наборе данных этот признак содержит наибольшее число пропусков.

In [153]:
data['is_apartment'].unique()
Out[153]:
array([nan, False, True], dtype=object)

Относится ли квартира к апартаментам — вопрос юридический. В апартаментах нельзя оформить постоянную регистрацию и за них нельзя получить налоговый вычет. Эти факты могут оказать влияние на выбор покупателей. Поэтому разумно полагать, что для всех апартаментов в объявлении было указано об их статусе в явном виде. Следовательно, если информация об апартаментах отсутствует, значит, объект недвижимости не является апартаментами.

Заменим все отсутствующие значения на значение False.

In [154]:
data['is_apartment'] = data['is_apartment'].fillna(False)
data['is_apartment'].unique()
Out[154]:
array([False,  True])
In [155]:
show_na()
Всего пропусков %
parks_nearest 15463 65.9
ponds_nearest 14435 61.5
balcony 11413 48.6
ceiling_height 9107 38.8
airports_nearest 5463 23.3
city_centers_nearest 5440 23.2
ponds_around_3000 5439 23.2
parks_around_3000 5439 23.2
days_exposition 3155 13.4
kitchen_area 2263 9.6
living_area 1903 8.1
floors_total 86 0.4
locality_type 49 0.2
locality_name 49 0.2
total_images 0 0.0
last_price 0 0.0
studio 0 0.0
is_apartment 0 0.0
floor 0 0.0
rooms 0 0.0
first_day_exposition 0 0.0
total_area 0 0.0
open_plan 0 0.0

Количество балконов¶

Признак balcony измеряется в порядковой шкале. Значения шкалы представляют собой ряд натуральных чисел. Значение ноль является меткой того, что у объекта недвижимости нет балконов. Среди всех записей почти в половине из них отсутствуют сведения о наличии балконов.

In [156]:
data['balcony'].sort_values().unique()
Out[156]:
array([ 0.,  1.,  2.,  3.,  4.,  5., nan])

Можно предположить, что отсутствие в объявлении о продаже объекта недвижимости сведений о количестве балконов является следствием отсутствия балконов у объекта недвижимости.

Заменим все отсутствующие значения на значение 0.

In [157]:
data['balcony'] = data['balcony'].fillna(0)
data['balcony'].sort_values().unique()
Out[157]:
array([0., 1., 2., 3., 4., 5.])
In [158]:
show_na()
Всего пропусков %
parks_nearest 15463 65.9
ponds_nearest 14435 61.5
ceiling_height 9107 38.8
airports_nearest 5463 23.3
city_centers_nearest 5440 23.2
ponds_around_3000 5439 23.2
parks_around_3000 5439 23.2
days_exposition 3155 13.4
kitchen_area 2263 9.6
living_area 1903 8.1
floors_total 86 0.4
locality_type 49 0.2
locality_name 49 0.2
total_images 0 0.0
balcony 0 0.0
last_price 0 0.0
studio 0 0.0
is_apartment 0 0.0
floor 0 0.0
rooms 0 0.0
first_day_exposition 0 0.0
total_area 0 0.0
open_plan 0 0.0

Название и тип населённого пункта¶

Название населённого пункта не указано для 49 записей.

Изучим записи с отсутствующими названиями населённых пунктов, у которых есть иные картографические данные. Определим местоположение объектов по величине расстояния до центра Санкт-Петербурга, расстояния до аэропорта, а также по количеству расположенных в пределах 3 км парков и водоёмов.

In [159]:
columns = ['floors_total', 'locality_name', 'city_centers_nearest',
           'airports_nearest', 'parks_around_3000', 'ponds_around_3000']

data[columns][data['locality_name'].isna() &
              data['city_centers_nearest'].notna()] \
              .sort_values('city_centers_nearest')
Out[159]:
floors_total locality_name city_centers_nearest airports_nearest parks_around_3000 ponds_around_3000
16610 5.0 NaN 1322.0 21219.0 1.0 3.0
22474 6.0 NaN 1780.0 23297.0 3.0 3.0
4189 4.0 NaN 3039.0 21774.0 1.0 1.0
19045 5.0 NaN 3312.0 21654.0 1.0 1.0
9821 2.0 NaN 3801.0 24953.0 1.0 2.0
4151 8.0 NaN 3902.0 25054.0 1.0 3.0
8568 6.0 NaN 4065.0 24233.0 1.0 0.0
11248 8.0 NaN 4069.0 25221.0 0.0 2.0
1097 5.0 NaN 4258.0 23478.0 0.0 0.0
20057 5.0 NaN 4258.0 23478.0 0.0 0.0
12936 5.0 NaN 4383.0 25680.0 3.0 0.0
10122 5.0 NaN 4474.0 25771.0 2.0 0.0
20654 5.0 NaN 4604.0 24385.0 1.0 0.0
7330 5.0 NaN 4627.0 25925.0 2.0 0.0
21333 6.0 NaN 4805.0 26090.0 0.0 1.0
4670 7.0 NaN 5382.0 26534.0 1.0 1.0
3574 5.0 NaN 8127.0 27419.0 0.0 1.0
18917 4.0 NaN 8429.0 21540.0 0.0 3.0
7114 5.0 NaN 8582.0 14031.0 0.0 0.0
16561 4.0 NaN 8619.0 21731.0 0.0 3.0
18526 7.0 NaN 8943.0 11206.0 0.0 0.0
23214 6.0 NaN 8943.0 11206.0 0.0 0.0
15866 5.0 NaN 9497.0 36380.0 1.0 3.0
5343 7.0 NaN 9538.0 10556.0 1.0 0.0
15686 5.0 NaN 9633.0 35920.0 2.0 3.0
17764 23.0 NaN 10976.0 36865.0 0.0 1.0
12879 12.0 NaN 12332.0 37123.0 0.0 0.0
7600 11.0 NaN 12332.0 37123.0 0.0 0.0
5707 24.0 NaN 16788.0 21460.0 0.0 1.0
14273 23.0 NaN 17369.0 22041.0 0.0 1.0
2603 24.0 NaN 17369.0 22041.0 0.0 1.0
2632 24.0 NaN 17369.0 22041.0 0.0 1.0
6765 24.0 NaN 17369.0 22041.0 0.0 1.0
22933 23.0 NaN 17369.0 22041.0 0.0 1.0
16499 24.0 NaN 17369.0 22041.0 0.0 1.0
19972 24.0 NaN 17369.0 22041.0 0.0 1.0
13223 24.0 NaN 17369.0 22041.0 0.0 1.0
13690 2.0 NaN 23659.0 20234.0 0.0 2.0
8986 NaN NaN 31813.0 19659.0 0.0 0.0
21119 4.0 NaN 31897.0 19744.0 0.0 0.0
21276 3.0 NaN 41294.0 60195.0 0.0 0.0

Расстояние от всех объектов недвижимости до центра Санкт-Петербурга находятся в диапазоне 1322—41 294 м.

Узнаем, на каком расстоянии от центра Санкт-Петербурга находятся объекты недвижимости, расположенные в пределах Санкт-Петербурга.

In [160]:
data.loc[(data['locality_name'] == 'Санкт-Петербург') &
         data['city_centers_nearest'].notna(),
         'city_centers_nearest'].sort_values().tail()
Out[160]:
11652    28644.0
19892    28806.0
16787    29263.0
13031    29343.0
12160    29493.0
Name: city_centers_nearest, dtype: float64

Максимально удалённый от центра Санкт-Петербурга объект недвижимости, всё ещё находящийся в пределах города, расположен на расстоянии 29 493 м.

Узнаем теперь, на каком расстоянии от центра Санкт-Петербурга находятся объекты недвижимости, расположенные вокруг Санкт-Петербурга.

In [161]:
data.loc[data['locality_name'].notna() &
         (data['locality_name'] != 'Санкт-Петербург') &
         data['city_centers_nearest'].notna(),
         'city_centers_nearest'].sort_values().head()
Out[161]:
18432    17012.0
6359     17017.0
8392     17231.0
4760     17231.0
1386     17231.0
Name: city_centers_nearest, dtype: float64

Самый ближайший к центру Санкт-Петербурга объект недвижимости, расположенный за его пределами, находится на расстоянии 17 012 м. Таким образом, все объекты недвижимости, расположенные на расстоянии менее 17 012 м, находятся в Санкт-Петербурге.

Выясним теперь, где могут быть расположены объекты недвижимости, расстояние от которых до центра Санкт-Петербурга находится в диапазоне 17 369—41 294 м.

Определим местонахождение объектов недвижимости, расположенных от центра Санкт-Петербурга на расстоянии 17 369 м и от аэропорта на расстоянии 22 041 м.

In [162]:
data.loc[data['locality_name'].notna() &
         (data['city_centers_nearest'] == 17369) &
         (data['airports_nearest'] == 22041),
         'locality_name'].unique()
Out[162]:
array(['Санкт-Петербург'], dtype=object)

Определим местонахождение объектов недвижимости, расположенных от центра Санкт-Петербурга на расстоянии 23 659 м и от аэропорта на расстоянии 20 234 м.

In [163]:
data.loc[data['locality_name'].notna() &
         (data['city_centers_nearest'] > 23630) &
         (data['city_centers_nearest'] < 23690) &
         (data['airports_nearest'] > 20200) &
         (data['airports_nearest'] < 20260),
         'locality_name'].unique()
Out[163]:
array(['Санкт-Петербург'], dtype=object)

Для всех объектов недвижимости, расстояние от которых до центра Санкт-Петербурга меньше 23 660 м, указываем местонахождение "Санкт-Петербург", тип населённого пункта — "город".

In [164]:
data.loc[data['locality_name'].isna() &
         (data['city_centers_nearest'] < 23660),
         'locality_name'] = data['locality_name'].fillna('Санкт-Петербург')

data.loc[data['locality_type'].isna() &
         (data['city_centers_nearest'] < 23660),
         'locality_type'] = data['locality_type'].fillna('город')

Определим местонахождение объектов недвижимости, расположенных от центра Санкт-Петербурга на расстоянии 31 813 м и 31 897 м и от аэропорта на расстоянии 19 756 м и 19 744 м, соответственно, вокруг которых нет парков.

In [165]:
data.loc[data['locality_name'].notna() &
         (data['city_centers_nearest'] > 31600) &
         (data['city_centers_nearest'] < 32000) &
         (data['airports_nearest'] > 19400) &
         (data['airports_nearest'] < 19900) &
         (data['parks_around_3000'] == 0),
         'locality_name'].unique()
Out[165]:
array(['Пушкин'], dtype=object)
In [166]:
data.loc[data['locality_name'].notna() &
         (data['locality_name'] == 'Пушкин'),
         'locality_type'].unique()
Out[166]:
array(['город'], dtype=object)

Для объектов недвижимости, расположенных от центра Санкт-Петербурга на расстоянии 31 813 м и 31 897 м, указываем местонахождение "Пушкин", тип населённого пункта — "город".

In [167]:
data.loc[data['locality_name'].isna() &
         ((data['city_centers_nearest'] == 31813) |
          (data['city_centers_nearest'] == 31897)),
         'locality_name'] = data['locality_name'].fillna('Пушкин')

data.loc[data['locality_type'].isna() &
         ((data['city_centers_nearest'] == 31813) |
          (data['city_centers_nearest'] == 31897)),
         'locality_type'] = data['locality_type'].fillna('город')

Определим местонахождение объектов недвижимости, расположенных от центра Санкт-Петербурга на расстоянии 41 294 м и от аэропорта на расстоянии 60 195 м, вокруг которых нет водоёмов.

In [168]:
data.loc[data['locality_name'].notna() &
         (data['city_centers_nearest'] > 39000) &
         (data['city_centers_nearest'] < 43000) &
         (data['airports_nearest'] > 58000) &
         (data['airports_nearest'] < 62000) &
         (data['ponds_around_3000'] == 0),
         'locality_name'].unique()
Out[168]:
array(['Репино'], dtype=object)
In [169]:
data.loc[data['locality_name'].notna() &
         (data['locality_name'] == 'Репино'),
         'locality_type'].unique()
Out[169]:
array(['посёлок'], dtype=object)

Для объектов недвижимости, расположенных от центра Санкт-Петербурга на расстоянии 41 294 м, указываем местонахождение "Репино", тип населённого пункта — "посёлок".

In [170]:
data.loc[data['locality_name'].isna() &
         (data['city_centers_nearest'] == 41294),
         'locality_name'] = data['locality_name'].fillna('Репино')

data.loc[data['locality_type'].isna() &
         (data['city_centers_nearest'] == 41294),
         'locality_type'] = data['locality_type'].fillna('посёлок')
In [171]:
len(data[data['locality_name'].isna() & data['city_centers_nearest'].notna()])
Out[171]:
0

Ещё для 8 объектов недвижимости не указано название населённого пункта, но для них также отсутствуют иные картографические данные.

In [172]:
columns = ['floors_total', 'locality_name', 'city_centers_nearest',
           'airports_nearest', 'parks_around_3000', 'ponds_around_3000']

data[columns][data['locality_name'].isna()]
Out[172]:
floors_total locality_name city_centers_nearest airports_nearest parks_around_3000 ponds_around_3000
2033 4.0 NaN NaN NaN NaN NaN
14342 4.0 NaN NaN NaN NaN NaN
17535 9.0 NaN NaN NaN NaN NaN
20382 5.0 NaN NaN NaN NaN NaN
20590 4.0 NaN NaN NaN NaN NaN
21715 9.0 NaN NaN NaN NaN NaN
21898 9.0 NaN NaN NaN NaN NaN
22717 16.0 NaN NaN NaN NaN NaN

Поскольку не удаётся с большой долей вероятности предположить местонахождение этих объектов, записи о данных объектах необходимо удалить. И необходимо убедиться, что изменения в данных не привели к ошибкам.

In [173]:
data.drop(index=data[data['locality_name'].isna()].index,
          inplace=True)

data['locality_name'].isna().sum()
Out[173]:
0
In [174]:
data['locality_type'].isna().sum()
Out[174]:
0
In [175]:
list(data['locality_name'].sort_values().unique())
Out[175]:
['Агалатово',
 'Александровская',
 'Алексеевка',
 'Аннино',
 'Аро',
 'Барышево',
 'Батово',
 'Бегуницы',
 'Белогорка',
 'Белоостров',
 'Бокситогорск',
 'Большая Вруда',
 'Большая Ижора',
 'Большая Пустомержа',
 'Большие Колпаны',
 'Большое Рейзино',
 'Большой Сабск',
 'Бор',
 'Борисова Грива',
 'Бугры',
 'Будогощь',
 'Ваганово',
 'Важины',
 'Вартемяги',
 'Вахнова Кара',
 'Вещево',
 'Виллози',
 'Вознесенье',
 'Возрождение',
 'Войсковицы',
 'Войскорово',
 'Володарское',
 'Волосово',
 'Волхов',
 'Всеволожск',
 'Выборг',
 'Вырица',
 'Выскатка',
 'Высокоключевой',
 'Высоцк',
 'Гаврилово',
 'Гарболово',
 'Гатчина',
 'Гладкое',
 'Глажево',
 'Глебычево',
 'Глинка',
 'Гончарово',
 'Горбунки',
 'Гостилицы',
 'Громово',
 'Дзержинского',
 'Дружная Горка',
 'Дружноселье',
 'Дубровка',
 'Елизаветино',
 'Ефимовский',
 'Жилгородок',
 'Житково',
 'Заводской',
 'Заклинье',
 'Заневка',
 'Запорожское',
 'Зеленогорск',
 'Зимитицы',
 'Ивангород',
 'Извара',
 'Ильичёво',
 'Иссад',
 'Калитино',
 'Каложицы',
 'Кальтино',
 'Каменногорск',
 'Камышовка',
 'Каськово',
 'Келози',
 'Кикерино',
 'Кингисепп',
 'Кингисеппский',
 'Кипень',
 'Кириши',
 'Кировск',
 'Кирпичное',
 'Кисельня',
 'Кобралово',
 'Кобринское',
 'Колпино',
 'Колтуши',
 'Коммунар',
 'Коммунары',
 'Кондратьево',
 'Копорье',
 'Коркино',
 'Корнево',
 'Коробицыно',
 'Котельский',
 'Котлы',
 'Красная Долина',
 'Красное Село',
 'Красносельское',
 'Красный Бор',
 'Кривко',
 'Кронштадт',
 'Кудрово',
 'Кузнечное',
 'Кузьмолово',
 'Кузьмоловский',
 'Курковицы',
 'Куровицы',
 'Куттузи',
 'Лаврики',
 'Лаголово',
 'Лампово',
 'Лебяжье',
 'Левашово',
 'Ленинское',
 'Лесколово',
 'Лесное',
 'Лесогорский',
 'Лисий Нос',
 'Лодейное Поле',
 'Ломоносов',
 'Лопухинка',
 'Луга',
 'Лужайка',
 'Лукаши',
 'Лупполово',
 'Любань',
 'Малое Верево',
 'Малое Карлино',
 'Малые Колпаны',
 'Мануйлово',
 'Мга',
 'Мельниково',
 'Меньково',
 'Металлострой',
 'Мины',
 'Мистолово',
 'Мичуринское',
 'Молодцово',
 'Молодёжное',
 'Мурино',
 'Мыза-Ивановка',
 'Назия',
 'Ненимяки',
 'Нижние Осельки',
 'Нижняя',
 'Низино',
 'Никольский',
 'Никольское',
 'Новая Ладога',
 'Новогорелово',
 'Новое Девяткино',
 'Новолисино',
 'Новоселье',
 'Новый Свет',
 'Новый Учхоз',
 'Нурма',
 'Оредеж',
 'Оржицы',
 'Отрадное',
 'Павлово',
 'Павловск',
 'Пансионат Зелёный Бор',
 'Парголово',
 'Парицы',
 'Паша',
 'Пельгора',
 'Пеники',
 'Первомайское',
 'Перово',
 'Песочный',
 'Петергоф',
 'Петро-Славянка',
 'Петровское',
 'Пижма',
 'Пикалёво',
 'Пикколово',
 'Платформа 69-й километр',
 'Плодовое',
 'Плоское',
 'Победа',
 'Подпорожье',
 'Поляны',
 'Понтонный',
 'Почап',
 'Починок',
 'Приветнинское',
 'Пригородный',
 'Приладожский',
 'Приморск',
 'Приозерск',
 'Пудомяги',
 'Пудость',
 'Пустынка',
 'Путилово',
 'Пушкин',
 'Пушное',
 'Пчева',
 'Пчевжа',
 'Рабитицы',
 'Разбегаево',
 'Раздолье',
 'Разметелево',
 'Рапполово',
 'Рахья',
 'Реброво',
 'Репино',
 'Рождествено',
 'Романовка',
 'Ромашки',
 'Ропша',
 'Рощино',
 'Русско',
 'Русско-Высоцкое',
 'Рябово',
 'Санкт-Петербург',
 'Сапёрное',
 'Сапёрный',
 'Светогорск',
 'Свирь',
 'Свирьстрой',
 'Севастьяново',
 'Селезнёво',
 'Сельцо',
 'Семиозерье',
 'Семрино',
 'Серебрянский',
 'Сертолово',
 'Сестрорецк',
 'Сиверский',
 'Сижно',
 'Синявино',
 'Сланцы',
 'Снегирёвка',
 'Советский',
 'Совхозный',
 'Сосново',
 'Сосновый Бор',
 'Старая',
 'Старая Ладога',
 'Старая Малукса',
 'Старая Пустошь',
 'Старое Хинколово',
 'Старополье',
 'Старосиверская',
 'Старые Бегуницы',
 'Стеклянный',
 'Стрельна',
 'Суйда',
 'Сумино',
 'Суоранда',
 'Суходолье',
 'Сяськелево',
 'Сясьстрой',
 'Тайцы',
 'Тарасово',
 'Тельмана',
 'Терволово',
 'Терпилицы',
 'Тихвин',
 'Тихковицы',
 'Тойворово',
 'Токсово',
 'Торковичи',
 'Торосово',
 'Торошковичи',
 'Торфяное',
 'Тосно',
 'Трубников Бор',
 'Тёсово-4',
 'Углово',
 'Ульяновка',
 'Усть-Ижора',
 'Усть-Луга',
 'Ушаки',
 'Фалилеево',
 'Форносово',
 'Форт Красная Горка',
 'Фёдоровское',
 'Хапо-Ое',
 'Хязельки',
 'Цвелодубово',
 'Цвылёво',
 'Чудской Бор',
 'Шлиссельбург',
 'Шпаньково',
 'Шугозеро',
 'Шум',
 'Шушары',
 'Щеглово',
 'Юкки',
 'Ялгино',
 'Яльгелево',
 'Ям-Тесово',
 'Янино-1',
 'имени Морозова',
 'имени Свердлова']
In [176]:
data['locality_type'].sort_values().unique()
Out[176]:
array(['город', 'городской посёлок', 'деревня', 'посёлок',
       'посёлок при железнодорожной станции', 'село'], dtype=object)
In [177]:
show_na()
Всего пропусков %
parks_nearest 15455 65.9
ponds_nearest 14427 61.5
ceiling_height 9101 38.8
airports_nearest 5455 23.2
city_centers_nearest 5432 23.1
ponds_around_3000 5431 23.1
parks_around_3000 5431 23.1
days_exposition 3154 13.4
kitchen_area 2261 9.6
living_area 1902 8.1
floors_total 86 0.4
total_images 0 0.0
locality_name 0 0.0
open_plan 0 0.0
balcony 0 0.0
last_price 0 0.0
studio 0 0.0
is_apartment 0 0.0
floor 0 0.0
rooms 0 0.0
first_day_exposition 0 0.0
total_area 0 0.0
locality_type 0 0.0

Расстояние до ближайшего парка¶

Среди значений признака parks_around_3000 есть значение 0, которое является меткой, обозначающей отсутствие парка в радиусе 3 км от объекта недвижимости.

In [178]:
data['parks_around_3000'].sort_values().unique()
Out[178]:
array([ 0.,  1.,  2.,  3., nan])

Узнаем, в каком количестве записей указано количество парков в радиусе 3 км равное 0, но не указано расстояние до них.

In [179]:
len(data[data['parks_nearest'].isna() & (data['parks_around_3000'] == 0)])
Out[179]:
10024

10 024 объекта недвижимости не имеют в радиусе 3 км ни одного парка. Для этих случаев заполним признак parks_nearest значением 0, которое с одной стороны не будет противоречить физической природе величины (расстояние есть величина неотрицательная), а с другой отличаться от допустимых значений, установленных критерием, что расстояние до ближайшего парка не должно быть меньше 10 м.

In [180]:
data.loc[data['parks_nearest'].isna() &
         (data['parks_around_3000'] == 0),
         'parks_nearest'] = data.loc[data['parks_nearest'].isna() &
                                     (data['parks_around_3000'] == 0),
                                     'parks_nearest'].fillna(0)

len(data[data['parks_nearest'].isna() & (data['parks_around_3000'] == 0)])
Out[180]:
0
In [181]:
show_na()
Всего пропусков %
ponds_nearest 14427 61.5
ceiling_height 9101 38.8
airports_nearest 5455 23.2
city_centers_nearest 5432 23.1
ponds_around_3000 5431 23.1
parks_nearest 5431 23.1
parks_around_3000 5431 23.1
days_exposition 3154 13.4
kitchen_area 2261 9.6
living_area 1902 8.1
floors_total 86 0.4
total_images 0 0.0
locality_name 0 0.0
open_plan 0 0.0
balcony 0 0.0
last_price 0 0.0
studio 0 0.0
is_apartment 0 0.0
floor 0 0.0
rooms 0 0.0
first_day_exposition 0 0.0
total_area 0 0.0
locality_type 0 0.0

Расстояние до ближайшего водоёма¶

Среди значений признака ponds_around_3000 есть значение 0, которое является меткой, обозначающей отсутствие водоёма в радиусе 3 км от объекта недвижимости.

In [182]:
data['ponds_around_3000'].sort_values().unique()
Out[182]:
array([ 0.,  1.,  2.,  3., nan])

Узнаем, в каком количестве записей указано количество водоёмов в радиусе 3 км равное 0, но не указано расстояние до них.

In [183]:
len(data[data['ponds_nearest'].isna() & (data['ponds_around_3000'] == 0)])
Out[183]:
8996

8996 объектов недвижимости не имеют в радиусе 3 км ни одного водоёма. Для этих случаев заполним признак ponds_nearest значением 0, которое с одной стороны не будет противоречить физической природе величины (расстояние есть величина неотрицательная), а с другой — как и для признака parks_nearest — отличаться от значения 10 м.

In [184]:
data.loc[data['ponds_nearest'].isna() &
         (data['ponds_around_3000'] == 0),
         'ponds_nearest'] = data.loc[data['ponds_nearest'].isna() &
                                     (data['ponds_around_3000'] == 0),
                                     'ponds_nearest'].fillna(0)

len(data[data['ponds_nearest'].isna() & (data['ponds_around_3000'] == 0)])
Out[184]:
0
In [185]:
show_na()
Всего пропусков %
ceiling_height 9101 38.8
airports_nearest 5455 23.2
city_centers_nearest 5432 23.1
ponds_nearest 5431 23.1
ponds_around_3000 5431 23.1
parks_nearest 5431 23.1
parks_around_3000 5431 23.1
days_exposition 3154 13.4
kitchen_area 2261 9.6
living_area 1902 8.1
floors_total 86 0.4
total_images 0 0.0
locality_name 0 0.0
open_plan 0 0.0
balcony 0 0.0
last_price 0 0.0
studio 0 0.0
is_apartment 0 0.0
floor 0 0.0
rooms 0 0.0
first_day_exposition 0 0.0
total_area 0 0.0
locality_type 0 0.0

Расстояние до центра Санкт-Петербурга¶

В 5432 записях не указано расстояние до центра Санкт-Петербурга. Из них только одна запись имеет данные о расстоянии до аэропорта.

In [186]:
columns = ['floors_total', 'locality_name',
           'city_centers_nearest', 'airports_nearest']

data[columns][data['city_centers_nearest'].isna() &
              data['airports_nearest'].notna()]
Out[186]:
floors_total locality_name city_centers_nearest airports_nearest
20190 3.0 Пушкин NaN 15527.0

Теперь определим местонахождение объектов недвижимости в Пушкине, расположенных от аэропорта на расстоянии 15 527 м.

In [187]:
data[columns][(data['locality_name'] == 'Пушкин') &
              (data['airports_nearest'] > 15500) &
              (data['airports_nearest'] < 15600)] \
              .sort_values('airports_nearest')
Out[187]:
floors_total locality_name city_centers_nearest airports_nearest
17214 3.0 Пушкин 27673.0 15520.0
4870 4.0 Пушкин 27677.0 15523.0
20190 3.0 Пушкин NaN 15527.0
8997 4.0 Пушкин 27704.0 15550.0
12526 3.0 Пушкин 27734.0 15580.0
20314 4.0 Пушкин 27749.0 15595.0

Заметим, что расстояния от зданий до центра Санкт-Петербурга изменяются на такую же величину, что и расстояния до аэропорта. Кроме того, этажность домов составляет 3—4 этажа. Вероятно, дома располагаются рядом: на одной улице или в одном микрорайоне. Поэтому при изменении расстояния до аэропорта на (15 527 м − 15 523 м) = 4 м, расстояние до центра Санкт-Петербурга также должно измениться на 4 м, и составит 27 681 м.

Заполним отсутствующее значение расстояния до центра Санкт-Петербурга значением 27 681 м.

In [188]:
data.loc[data['city_centers_nearest'].isna() &
         data['airports_nearest'].notna(),
         'city_centers_nearest'] = 27681
In [189]:
show_na()
Всего пропусков %
ceiling_height 9101 38.8
airports_nearest 5455 23.2
ponds_nearest 5431 23.1
ponds_around_3000 5431 23.1
parks_nearest 5431 23.1
parks_around_3000 5431 23.1
city_centers_nearest 5431 23.1
days_exposition 3154 13.4
kitchen_area 2261 9.6
living_area 1902 8.1
floors_total 86 0.4
total_images 0 0.0
locality_name 0 0.0
open_plan 0 0.0
balcony 0 0.0
last_price 0 0.0
studio 0 0.0
is_apartment 0 0.0
floor 0 0.0
rooms 0 0.0
first_day_exposition 0 0.0
total_area 0 0.0
locality_type 0 0.0

Расстояние до аэропорта¶

В 5463 записях не указано расстояние до аэропорта Пулково. Из них только 24 записи имеют сведения о расстоянии до центра Санкт-Петербурга и другие картографические данные.

In [190]:
data.loc[data['airports_nearest'].isna() &
         data['city_centers_nearest'].notna(),
         'city_centers_nearest'].count()
Out[190]:
24
In [191]:
columns = ['floors_total', 'locality_name', 'city_centers_nearest',
           'airports_nearest', 'parks_around_3000', 'parks_nearest',
           'ponds_around_3000', 'ponds_nearest']

data[columns][data['airports_nearest'].isna() &
              data['city_centers_nearest'].notna()] \
              .sort_values('city_centers_nearest')
Out[191]:
floors_total locality_name city_centers_nearest airports_nearest parks_around_3000 parks_nearest ponds_around_3000 ponds_nearest
9880 5.0 Санкт-Петербург 4892.0 NaN 0.0 0.0 2.0 369.0
7521 7.0 Санкт-Петербург 5735.0 NaN 2.0 110.0 0.0 0.0
8018 7.0 Санкт-Петербург 5735.0 NaN 2.0 110.0 0.0 0.0
8628 6.0 Санкт-Петербург 5735.0 NaN 2.0 110.0 0.0 0.0
13106 7.0 Санкт-Петербург 5735.0 NaN 2.0 110.0 0.0 0.0
12401 7.0 Санкт-Петербург 5735.0 NaN 2.0 110.0 0.0 0.0
11457 10.0 Санкт-Петербург 9734.0 NaN 2.0 469.0 3.0 263.0
974 7.0 Санкт-Петербург 9734.0 NaN 2.0 469.0 3.0 263.0
21769 25.0 Санкт-Петербург 9734.0 NaN 2.0 469.0 3.0 263.0
9054 10.0 Санкт-Петербург 9734.0 NaN 2.0 469.0 3.0 263.0
16825 16.0 Санкт-Петербург 9734.0 NaN 2.0 469.0 3.0 263.0
14276 25.0 Санкт-Петербург 9734.0 NaN 2.0 469.0 3.0 263.0
21075 5.0 Санкт-Петербург 11246.0 NaN 0.0 0.0 0.0 0.0
23124 5.0 Санкт-Петербург 11246.0 NaN 0.0 0.0 0.0 0.0
11446 5.0 Санкт-Петербург 11835.0 NaN 1.0 267.0 1.0 601.0
16470 19.0 Санкт-Петербург 13355.0 NaN 1.0 735.0 0.0 0.0
16927 23.0 Санкт-Петербург 13355.0 NaN 1.0 735.0 0.0 0.0
18222 23.0 Санкт-Петербург 13355.0 NaN 1.0 735.0 0.0 0.0
18557 19.0 Санкт-Петербург 13355.0 NaN 1.0 735.0 0.0 0.0
7542 23.0 Санкт-Петербург 13355.0 NaN 1.0 735.0 0.0 0.0
2415 23.0 Санкт-Петербург 13355.0 NaN 1.0 735.0 0.0 0.0
22790 23.0 Санкт-Петербург 13355.0 NaN 1.0 735.0 0.0 0.0
733 21.0 Санкт-Петербург 13355.0 NaN 1.0 735.0 0.0 0.0
10669 5.0 Санкт-Петербург 21377.0 NaN 0.0 0.0 0.0 0.0

Все объекты расположены в Санкт-Петербурге на расстоянии от центра города в диапазоне 4892—21 377 м.

Выясним, на каком расстоянии от аэропорта находятся объекты недвижимости в Санкт-Петербурге, расположенные на расстоянии 4892 м от центра города, вокруг которых нет парков, но есть 2 водоёма.

In [192]:
data[columns][(data['locality_name'] == 'Санкт-Петербург') &
              (data['city_centers_nearest'] > 4850) &
              (data['city_centers_nearest'] < 4930) &
              (data['ponds_around_3000'] == 2) &
              (data['parks_around_3000'] == 0)] \
              .sort_values('city_centers_nearest')
Out[192]:
floors_total locality_name city_centers_nearest airports_nearest parks_around_3000 parks_nearest ponds_around_3000 ponds_nearest
351 5.0 Санкт-Петербург 4855.0 32758.0 0.0 0.0 2.0 519.0
9880 5.0 Санкт-Петербург 4892.0 NaN 0.0 0.0 2.0 369.0
13607 5.0 Санкт-Петербург 4920.0 32273.0 0.0 0.0 2.0 834.0

Заменим отсутствующее значение на значение 32 500 м (среднее арифметическое значение, рассчитанное с точностью до 100 м).

In [193]:
data.loc[(data['locality_name'] == 'Санкт-Петербург') &
         (data['city_centers_nearest'] == 4892),
         'airports_nearest'] = 32500

data[columns][(data['locality_name'] == 'Санкт-Петербург') &
              (data['city_centers_nearest'] == 4892)]
Out[193]:
floors_total locality_name city_centers_nearest airports_nearest parks_around_3000 parks_nearest ponds_around_3000 ponds_nearest
9880 5.0 Санкт-Петербург 4892.0 32500.0 0.0 0.0 2.0 369.0

Выясним, на каком расстоянии от аэропорта находятся объекты недвижимости в Санкт-Петербурге, расположенные на расстоянии 5735 м от центра города, вокруг которых нет водоёмов, но есть 2 парка.

In [194]:
data[columns][(data['locality_name'] == 'Санкт-Петербург') &
              (data['city_centers_nearest'] > 5700) &
              (data['city_centers_nearest'] < 5770) &
              (data['parks_around_3000'] == 2) &
              (data['ponds_around_3000'] == 0)] \
              .sort_values('city_centers_nearest')
Out[194]:
floors_total locality_name city_centers_nearest airports_nearest parks_around_3000 parks_nearest ponds_around_3000 ponds_nearest
1212 4.0 Санкт-Петербург 5718.0 25300.0 2.0 381.0 0.0 0.0
20389 4.0 Санкт-Петербург 5718.0 25300.0 2.0 381.0 0.0 0.0
7521 7.0 Санкт-Петербург 5735.0 NaN 2.0 110.0 0.0 0.0
8018 7.0 Санкт-Петербург 5735.0 NaN 2.0 110.0 0.0 0.0
8628 6.0 Санкт-Петербург 5735.0 NaN 2.0 110.0 0.0 0.0
12401 7.0 Санкт-Петербург 5735.0 NaN 2.0 110.0 0.0 0.0
13106 7.0 Санкт-Петербург 5735.0 NaN 2.0 110.0 0.0 0.0
736 6.0 Санкт-Петербург 5741.0 25323.0 2.0 393.0 0.0 0.0
22025 6.0 Санкт-Петербург 5741.0 25323.0 2.0 393.0 0.0 0.0
14879 5.0 Санкт-Петербург 5744.0 16869.0 2.0 300.0 0.0 0.0
16169 6.0 Санкт-Петербург 5746.0 25469.0 2.0 93.0 0.0 0.0
8842 8.0 Санкт-Петербург 5765.0 25846.0 2.0 250.0 0.0 0.0
13816 8.0 Санкт-Петербург 5765.0 25846.0 2.0 250.0 0.0 0.0

Близкими по расположению являются 6—7-этажные здания, которые расположены на расстоянии 25 300—25 469 м от аэропорта. Заполним отсутствующее значение на значение 25 350 м.

In [195]:
data.loc[(data['city_centers_nearest'] == 5735) &
         (data['locality_name'] == 'Санкт-Петербург'),
         'airports_nearest'] = 25350

data[columns][(data['locality_name'] == 'Санкт-Петербург') &
              (data['city_centers_nearest'] == 5735)]
Out[195]:
floors_total locality_name city_centers_nearest airports_nearest parks_around_3000 parks_nearest ponds_around_3000 ponds_nearest
7521 7.0 Санкт-Петербург 5735.0 25350.0 2.0 110.0 0.0 0.0
8018 7.0 Санкт-Петербург 5735.0 25350.0 2.0 110.0 0.0 0.0
8628 6.0 Санкт-Петербург 5735.0 25350.0 2.0 110.0 0.0 0.0
12401 7.0 Санкт-Петербург 5735.0 25350.0 2.0 110.0 0.0 0.0
13106 7.0 Санкт-Петербург 5735.0 25350.0 2.0 110.0 0.0 0.0

Выясним, на каком расстоянии от аэропорта находятся объекты недвижимости в Санкт-Петербурге, расположенные на расстоянии 9734 м от центра города, вокруг которых есть 2 парка и 3 водоёма.

In [196]:
data[columns][(data['locality_name'] == 'Санкт-Петербург') &
              (data['city_centers_nearest'] > 9700) &
              (data['city_centers_nearest'] < 9770) &
              (data['parks_around_3000'] == 2) &
              (data['ponds_around_3000'] == 3)] \
              .sort_values('city_centers_nearest')
Out[196]:
floors_total locality_name city_centers_nearest airports_nearest parks_around_3000 parks_nearest ponds_around_3000 ponds_nearest
13582 5.0 Санкт-Петербург 9702.0 35836.0 2.0 588.0 3.0 316.0
15153 5.0 Санкт-Петербург 9724.0 36011.0 2.0 473.0 3.0 483.0
974 7.0 Санкт-Петербург 9734.0 NaN 2.0 469.0 3.0 263.0
9054 10.0 Санкт-Петербург 9734.0 NaN 2.0 469.0 3.0 263.0
11457 10.0 Санкт-Петербург 9734.0 NaN 2.0 469.0 3.0 263.0
14276 25.0 Санкт-Петербург 9734.0 NaN 2.0 469.0 3.0 263.0
16825 16.0 Санкт-Петербург 9734.0 NaN 2.0 469.0 3.0 263.0
21769 25.0 Санкт-Петербург 9734.0 NaN 2.0 469.0 3.0 263.0

Заменим отсутствующее значение на значение 35 900 м (среднее арифметическое значение, рассчитанное с точностью до 100 м).

In [197]:
data.loc[(data['city_centers_nearest'] == 9734) &
         (data['locality_name'] == 'Санкт-Петербург'),
         'airports_nearest'] = 35900

data[columns][(data['locality_name'] == 'Санкт-Петербург') &
              (data['city_centers_nearest'] == 9734)]
Out[197]:
floors_total locality_name city_centers_nearest airports_nearest parks_around_3000 parks_nearest ponds_around_3000 ponds_nearest
974 7.0 Санкт-Петербург 9734.0 35900.0 2.0 469.0 3.0 263.0
9054 10.0 Санкт-Петербург 9734.0 35900.0 2.0 469.0 3.0 263.0
10959 5.0 Санкт-Петербург 9734.0 35900.0 0.0 0.0 1.0 431.0
11457 10.0 Санкт-Петербург 9734.0 35900.0 2.0 469.0 3.0 263.0
14276 25.0 Санкт-Петербург 9734.0 35900.0 2.0 469.0 3.0 263.0
16825 16.0 Санкт-Петербург 9734.0 35900.0 2.0 469.0 3.0 263.0
19430 5.0 Санкт-Петербург 9734.0 35900.0 0.0 0.0 1.0 431.0
21769 25.0 Санкт-Петербург 9734.0 35900.0 2.0 469.0 3.0 263.0

Выясним, на каком расстоянии от аэропорта находятся 5-этажные здания в Санкт-Петербурге, расположенные на расстоянии 11 246 м от центра города, вокруг которых нет парков и водоёмов.

In [198]:
data[columns][(data['locality_name'] == 'Санкт-Петербург') &
              (data['city_centers_nearest'] > 11200) &
              (data['city_centers_nearest'] < 11300) &
              (data['parks_around_3000'] == 0) &
              (data['ponds_around_3000'] == 0) &
              (data['floors_total'] == 5)] \
              .sort_values('airports_nearest')
Out[198]:
floors_total locality_name city_centers_nearest airports_nearest parks_around_3000 parks_nearest ponds_around_3000 ponds_nearest
4687 5.0 Санкт-Петербург 11246.0 9823.0 0.0 0.0 0.0 0.0
13888 5.0 Санкт-Петербург 11282.0 10875.0 0.0 0.0 0.0 0.0
18144 5.0 Санкт-Петербург 11282.0 10875.0 0.0 0.0 0.0 0.0
6706 5.0 Санкт-Петербург 11286.0 10877.0 0.0 0.0 0.0 0.0
3292 5.0 Санкт-Петербург 11247.0 14717.0 0.0 0.0 0.0 0.0
5470 5.0 Санкт-Петербург 11240.0 37499.0 0.0 0.0 0.0 0.0
20974 5.0 Санкт-Петербург 11211.0 39508.0 0.0 0.0 0.0 0.0
17827 5.0 Санкт-Петербург 11269.0 39566.0 0.0 0.0 0.0 0.0
17242 5.0 Санкт-Петербург 11282.0 41099.0 0.0 0.0 0.0 0.0
23401 5.0 Санкт-Петербург 11282.0 41099.0 0.0 0.0 0.0 0.0
21075 5.0 Санкт-Петербург 11246.0 NaN 0.0 0.0 0.0 0.0
23124 5.0 Санкт-Петербург 11246.0 NaN 0.0 0.0 0.0 0.0

Поскольку разброс возможных значений расстояния до аэропорта большой, рассчитаем среднее арифметическое имеющихся значений и заполним этим полученным средним отсутствующие значения.

In [199]:
mean_for_fillna = data.loc[(data['locality_name'] == 'Санкт-Петербург') &
                           (data['city_centers_nearest'] > 11220) &
                           (data['city_centers_nearest'] < 11270) &
                           (data['parks_around_3000'] == 0) &
                           (data['ponds_around_3000'] == 0) &
                           (data['floors_total'] == 5),
                           'airports_nearest'].mean().round(-2)

data.loc[(data['city_centers_nearest'] == 11246) &
         (data['locality_name'] == 'Санкт-Петербург'),
         'airports_nearest'] = data['airports_nearest'].fillna(mean_for_fillna)

data[columns][(data['locality_name'] == 'Санкт-Петербург') &
              (data['city_centers_nearest'] == 11246)]
Out[199]:
floors_total locality_name city_centers_nearest airports_nearest parks_around_3000 parks_nearest ponds_around_3000 ponds_nearest
4687 5.0 Санкт-Петербург 11246.0 9823.0 0.0 0.0 0.0 0.0
13307 10.0 Санкт-Петербург 11246.0 29080.0 1.0 546.0 1.0 593.0
21075 5.0 Санкт-Петербург 11246.0 25400.0 0.0 0.0 0.0 0.0
23124 5.0 Санкт-Петербург 11246.0 25400.0 0.0 0.0 0.0 0.0

Выясним, на каком расстоянии от аэропорта находятся 5-этажные здания в Санкт-Петербурге, расположенные на расстоянии 11 835 м от центра города, вокруг которых есть 1 парк и 1 водоём.

In [200]:
data[columns][(data['locality_name'] == 'Санкт-Петербург') &
              (data['city_centers_nearest'] > 11700) &
              (data['city_centers_nearest'] < 11870) &
              (data['parks_around_3000'] == 1) &
              (data['ponds_around_3000'] == 1) &
              (data['ponds_nearest'] > 500) &
              (data['ponds_nearest'] < 650) &
              (data['floors_total'] == 5)] \
              .sort_values('city_centers_nearest')
Out[200]:
floors_total locality_name city_centers_nearest airports_nearest parks_around_3000 parks_nearest ponds_around_3000 ponds_nearest
16634 5.0 Санкт-Петербург 11792.0 14771.0 1.0 318.0 1.0 571.0
22664 5.0 Санкт-Петербург 11792.0 14771.0 1.0 318.0 1.0 571.0
3791 5.0 Санкт-Петербург 11831.0 14730.0 1.0 322.0 1.0 596.0
11446 5.0 Санкт-Петербург 11835.0 NaN 1.0 267.0 1.0 601.0

Заменим отсутствующее значение на значение 14 750 м.

In [201]:
data.loc[(data['city_centers_nearest'] == 11835) &
         (data['locality_name'] == 'Санкт-Петербург'),
         'airports_nearest'] = 14750

data[columns][(data['locality_name'] == 'Санкт-Петербург') &
              (data['city_centers_nearest'] == 11835)]
Out[201]:
floors_total locality_name city_centers_nearest airports_nearest parks_around_3000 parks_nearest ponds_around_3000 ponds_nearest
11446 5.0 Санкт-Петербург 11835.0 14750.0 1.0 267.0 1.0 601.0

Выясним, на каком расстоянии от аэропорта находятся объекты недвижимости в Санкт-Петербурге, расположенные на расстоянии 13 355 м от центра города, вокруг которых нет водоёмов, но есть 1 парк.

In [202]:
data[columns][(data['locality_name'] == 'Санкт-Петербург') &
              (data['city_centers_nearest'] > 13250) &
              (data['city_centers_nearest'] < 13450) &
              (data['parks_around_3000'] == 1) &
              (data['ponds_around_3000'] == 0) &
              (data['parks_nearest'] > 650) &
              (data['parks_nearest'] < 850)] \
              .sort_values('city_centers_nearest')
Out[202]:
floors_total locality_name city_centers_nearest airports_nearest parks_around_3000 parks_nearest ponds_around_3000 ponds_nearest
733 21.0 Санкт-Петербург 13355.0 NaN 1.0 735.0 0.0 0.0
18557 19.0 Санкт-Петербург 13355.0 NaN 1.0 735.0 0.0 0.0
18222 23.0 Санкт-Петербург 13355.0 NaN 1.0 735.0 0.0 0.0
16927 23.0 Санкт-Петербург 13355.0 NaN 1.0 735.0 0.0 0.0
16470 19.0 Санкт-Петербург 13355.0 NaN 1.0 735.0 0.0 0.0
22790 23.0 Санкт-Петербург 13355.0 NaN 1.0 735.0 0.0 0.0
7542 23.0 Санкт-Петербург 13355.0 NaN 1.0 735.0 0.0 0.0
2415 23.0 Санкт-Петербург 13355.0 NaN 1.0 735.0 0.0 0.0
12106 13.0 Санкт-Петербург 13370.0 51443.0 1.0 805.0 0.0 0.0
13857 25.0 Санкт-Петербург 13370.0 51443.0 1.0 805.0 0.0 0.0
19517 16.0 Санкт-Петербург 13370.0 51443.0 1.0 805.0 0.0 0.0
7360 25.0 Санкт-Петербург 13370.0 51443.0 1.0 805.0 0.0 0.0
6562 17.0 Санкт-Петербург 13370.0 51443.0 1.0 805.0 0.0 0.0
18608 13.0 Санкт-Петербург 13370.0 51443.0 1.0 805.0 0.0 0.0
19290 16.0 Санкт-Петербург 13370.0 51443.0 1.0 805.0 0.0 0.0
9257 25.0 Санкт-Петербург 13370.0 51443.0 1.0 805.0 0.0 0.0
14782 17.0 Санкт-Петербург 13370.0 51443.0 1.0 805.0 0.0 0.0

Заменим отсутствующее значение на значение 51 400 м.

In [203]:
data.loc[(data['city_centers_nearest'] == 13355) &
         (data['locality_name'] == 'Санкт-Петербург'),
         'airports_nearest'] = 51400

data[columns][(data['locality_name'] == 'Санкт-Петербург') &
              (data['city_centers_nearest'] == 13355)]
Out[203]:
floors_total locality_name city_centers_nearest airports_nearest parks_around_3000 parks_nearest ponds_around_3000 ponds_nearest
733 21.0 Санкт-Петербург 13355.0 51400.0 1.0 735.0 0.0 0.0
2415 23.0 Санкт-Петербург 13355.0 51400.0 1.0 735.0 0.0 0.0
3916 5.0 Санкт-Петербург 13355.0 51400.0 2.0 186.0 2.0 347.0
7542 23.0 Санкт-Петербург 13355.0 51400.0 1.0 735.0 0.0 0.0
16470 19.0 Санкт-Петербург 13355.0 51400.0 1.0 735.0 0.0 0.0
16927 23.0 Санкт-Петербург 13355.0 51400.0 1.0 735.0 0.0 0.0
18222 23.0 Санкт-Петербург 13355.0 51400.0 1.0 735.0 0.0 0.0
18557 19.0 Санкт-Петербург 13355.0 51400.0 1.0 735.0 0.0 0.0
22790 23.0 Санкт-Петербург 13355.0 51400.0 1.0 735.0 0.0 0.0

Выясним, на каком расстоянии от аэропорта находятся 5-этажные здания в Санкт-Петербурге, расположенные на расстоянии 21 377 м от центра города, вокруг которых нет парков и водоёмов.

In [204]:
data[columns][(data['locality_name'] == 'Санкт-Петербург') &
              (data['city_centers_nearest'] > 21000) &
              (data['city_centers_nearest'] < 21500) &
              (data['parks_around_3000'] == 0) &
              (data['ponds_around_3000'] == 0) &
              (data['floors_total'] == 5)] \
              .sort_values('city_centers_nearest')
Out[204]:
floors_total locality_name city_centers_nearest airports_nearest parks_around_3000 parks_nearest ponds_around_3000 ponds_nearest
12534 5.0 Санкт-Петербург 21280.0 18118.0 0.0 0.0 0.0 0.0
10669 5.0 Санкт-Петербург 21377.0 NaN 0.0 0.0 0.0 0.0
13764 5.0 Санкт-Петербург 21497.0 17659.0 0.0 0.0 0.0 0.0

Заменим отсутствующее значение на значение 17 900 м (среднее арифметическое значение, рассчитанное с точностью до 100 м).

In [205]:
data.loc[(data['city_centers_nearest'] == 21377) &
         (data['locality_name'] == 'Санкт-Петербург'),
         'airports_nearest'] = 17900

data[columns][(data['locality_name'] == 'Санкт-Петербург') &
              (data['city_centers_nearest'] == 21377)]
Out[205]:
floors_total locality_name city_centers_nearest airports_nearest parks_around_3000 parks_nearest ponds_around_3000 ponds_nearest
10669 5.0 Санкт-Петербург 21377.0 17900.0 0.0 0.0 0.0 0.0
In [206]:
show_na()
Всего пропусков %
ceiling_height 9101 38.8
ponds_nearest 5431 23.1
ponds_around_3000 5431 23.1
parks_nearest 5431 23.1
parks_around_3000 5431 23.1
city_centers_nearest 5431 23.1
airports_nearest 5431 23.1
days_exposition 3154 13.4
kitchen_area 2261 9.6
living_area 1902 8.1
floors_total 86 0.4
total_images 0 0.0
locality_name 0 0.0
open_plan 0 0.0
balcony 0 0.0
last_price 0 0.0
studio 0 0.0
is_apartment 0 0.0
floor 0 0.0
rooms 0 0.0
first_day_exposition 0 0.0
total_area 0 0.0
locality_type 0 0.0

Этажность здания¶

В признаке floors_total отсутствуют значения в 86 записях. В 76 из них указаны картографические данные.

In [207]:
columns = ['floor', 'floors_total', 'locality_name', 'city_centers_nearest',
           'airports_nearest', 'parks_around_3000', 'parks_nearest',
           'ponds_around_3000', 'ponds_nearest']

data[columns][data['floors_total'].isna() &
              data['city_centers_nearest'].notna()] \
              .sort_values('city_centers_nearest')
Out[207]:
floor floors_total locality_name city_centers_nearest airports_nearest parks_around_3000 parks_nearest ponds_around_3000 ponds_nearest
2952 6 NaN Санкт-Петербург 3148.0 23606.0 0.0 0.0 0.0 0.0
10880 3 NaN Санкт-Петербург 3252.0 20160.0 2.0 320.0 1.0 976.0
22808 6 NaN Санкт-Петербург 4529.0 19095.0 0.0 0.0 0.0 0.0
23590 18 NaN Санкт-Петербург 4529.0 19095.0 0.0 0.0 0.0 0.0
18832 6 NaN Санкт-Петербург 4529.0 19095.0 0.0 0.0 0.0 0.0
... ... ... ... ... ... ... ... ... ...
12104 7 NaN Санкт-Петербург 25866.0 47303.0 1.0 251.0 1.0 350.0
10004 5 NaN Красное Село 28719.0 25295.0 3.0 362.0 0.0 0.0
15989 1 NaN Красное Село 28806.0 25382.0 0.0 0.0 0.0 0.0
8986 4 NaN Пушкин 31813.0 19659.0 0.0 0.0 0.0 0.0
3817 1 NaN Щеглово 34085.0 61908.0 0.0 0.0 0.0 0.0

76 rows × 9 columns

Для заполнения значений этажности зданий будем использовать известные значения этажности других зданий, расположенных на тех же расстояниях от центра Санкт-Петербурга и от аэропорта. Если таких зданий окажется несколько, то выбираем самое высокое здание (т. е. здание с максимальной этажностью). Заполняем этажность этим максимальным значением. В случае, если окажется, что этаж, на котором расположен объект недвижимости, выше чем самое высокое здание, то указываем в качестве этажности номер этажа. Таким образом, объект недвижимости получается расположенным на последнем этаже.

In [208]:
# Сделаем срез строк, содержащих отсутствующее значение признака `floors_total`,
# но имеющих данные о расстоянии до центра Санкт-Петербурга и до аэропорта
floors_total_na = data[data['floors_total'].isna() &
                       data['city_centers_nearest'].notna() &
                       data['airports_nearest'].notna()]

for index, row in floors_total_na.iterrows():        # Положим в переменные:
    distance_to_center = row['city_centers_nearest'] # значение расстояния до центра Санкт-Петербурга
    distance_to_airport = row['airports_nearest']    # значение расстояния до аэропорта
    floor_number = row['floor']                      # номер этажа, на котором расположен объект недвижимости

    # Выберем из имеющихся в наборе данных значений признака `floors_total`
    # максимальное значение среди всех зданий, расположенных на том же
    # расстоянии от аэропорта и центра Санкт-Петербурга,
    # что и здание неизвестной этажности
    floors_total_value = data.loc[
        data['floors_total'].notna() &
        (data['city_centers_nearest'] == distance_to_center) &
        (data['airports_nearest'] == distance_to_airport),
        'floors_total'].max()

    if floors_total_value >= floor_number:
    # Если этаж, на котором расположен объект недвижимости в здании с
    # неизвестной этажностью, меньше максимального значения этажности зданий,
    # то заполняем отсутствующее значение максимальным значением
        data.loc[data['floors_total'].isna() &
                 (data['city_centers_nearest'] == distance_to_center) &
                 (data['airports_nearest'] == distance_to_airport),
                 'floors_total'] = data['floors_total'].fillna(floors_total_value)

    elif floors_total_value < floor_number:
    # Если этаж, на котором расположен объект недвижимости в здании с
    # неизвестной этажностью, больше максимального значения этажности,
    # то заполняем отсутствующее значение максимальным значением среди
    # номеров этажей, на которых располагаются объекты недвижимости в
    # зданиях с неизвестной этажностью
        floor_number_max = floors_total_na.loc[
            (floors_total_na['city_centers_nearest'] == distance_to_center) &
            (floors_total_na['airports_nearest'] == distance_to_airport),
            'floor'].max()

        data.loc[data['floors_total'].isna() &
                 (data['city_centers_nearest'] == distance_to_center) &
                 (data['airports_nearest'] == distance_to_airport),
                 'floors_total'] = data['floors_total'].fillna(floor_number_max)
In [209]:
data['floors_total'].sort_values().unique()
Out[209]:
array([ 1.,  2.,  3.,  4.,  5.,  6.,  7.,  8.,  9., 10., 11., 12., 13.,
       14., 15., 16., 17., 18., 19., 20., 21., 22., 23., 24., 25., 26.,
       27., 28., 29., 35., nan])

Выясним, какие значения остались незаполненными.

In [210]:
data[columns][data['floors_total'].isna() &
              data['city_centers_nearest'].notna()] \
              .sort_values('city_centers_nearest')
Out[210]:
floor floors_total locality_name city_centers_nearest airports_nearest parks_around_3000 parks_nearest ponds_around_3000 ponds_nearest
10880 3 NaN Санкт-Петербург 3252.0 20160.0 2.0 320.0 1.0 976.0
18832 6 NaN Санкт-Петербург 4529.0 19095.0 0.0 0.0 0.0 0.0
22808 6 NaN Санкт-Петербург 4529.0 19095.0 0.0 0.0 0.0 0.0
23590 18 NaN Санкт-Петербург 4529.0 19095.0 0.0 0.0 0.0 0.0
6030 24 NaN Санкт-Петербург 14674.0 35234.0 0.0 0.0 1.0 844.0
11389 7 NaN Санкт-Петербург 14674.0 35234.0 0.0 0.0 1.0 844.0
13622 21 NaN Санкт-Петербург 14674.0 35234.0 0.0 0.0 1.0 844.0
21273 19 NaN Санкт-Петербург 14674.0 35234.0 0.0 0.0 1.0 844.0
12399 4 NaN Санкт-Петербург 18535.0 19533.0 1.0 375.0 0.0 0.0
10259 5 NaN Мурино 21888.0 51553.0 0.0 0.0 2.0 133.0
11425 4 NaN Мурино 21888.0 51553.0 0.0 0.0 2.0 133.0
15989 1 NaN Красное Село 28806.0 25382.0 0.0 0.0 0.0 0.0
8986 4 NaN Пушкин 31813.0 19659.0 0.0 0.0 0.0 0.0
3817 1 NaN Щеглово 34085.0 61908.0 0.0 0.0 0.0 0.0

Выясним, какова этажность зданий в Санкт-Петербурге, расположенных от центра города на расстоянии 3252 м и от аэропорта на расстоянии 20 160 м, вокруг которых есть 2 парка и 1 водоём.

In [211]:
data[columns][(data['city_centers_nearest'] > 3200) &
              (data['city_centers_nearest'] < 3300) &
              (data['airports_nearest'] > 19000) &
              (data['airports_nearest'] < 21000) &
              (data['parks_around_3000'] == 2) &
              (data['ponds_around_3000'] == 1)] \
              .sort_values('city_centers_nearest')
Out[211]:
floor floors_total locality_name city_centers_nearest airports_nearest parks_around_3000 parks_nearest ponds_around_3000 ponds_nearest
2122 2 4.0 Санкт-Петербург 3233.0 20628.0 2.0 261.0 1.0 819.0
10287 1 5.0 Санкт-Петербург 3238.0 20873.0 2.0 450.0 1.0 869.0
10880 3 NaN Санкт-Петербург 3252.0 20160.0 2.0 320.0 1.0 976.0
9500 6 6.0 Санкт-Петербург 3269.0 20904.0 2.0 482.0 1.0 849.0

Поскольку все найденные значения разные, заполним отсутствующее значение медианным значением — 5.

In [212]:
data.loc[data['floors_total'].isna() &
         (data['city_centers_nearest'] == 3252) &
         (data['airports_nearest'] == 20160),
         'floors_total'] = data['floors_total'].fillna(5)

data[columns][(data['city_centers_nearest'] == 3252) &
              (data['airports_nearest'] == 20160)]
Out[212]:
floor floors_total locality_name city_centers_nearest airports_nearest parks_around_3000 parks_nearest ponds_around_3000 ponds_nearest
10880 3 5.0 Санкт-Петербург 3252.0 20160.0 2.0 320.0 1.0 976.0

Выясним, какова этажность зданий в Санкт-Петербурге, расположенных от центра города на расстоянии 4529 м и от аэропорта на расстоянии 19 095 м, вокруг которых нет парков и водоёмов.

In [213]:
data[columns][(data['city_centers_nearest'] > 4500) &
              (data['city_centers_nearest'] < 4600) &
              (data['airports_nearest'] > 18840) &
              (data['airports_nearest'] < 19350) &
              (data['ponds_around_3000'] == 0) &
              (data['parks_around_3000'] == 0)] \
              .sort_values('city_centers_nearest')
Out[213]:
floor floors_total locality_name city_centers_nearest airports_nearest parks_around_3000 parks_nearest ponds_around_3000 ponds_nearest
6564 17 19.0 Санкт-Петербург 4529.0 18934.0 0.0 0.0 0.0 0.0
18832 6 NaN Санкт-Петербург 4529.0 19095.0 0.0 0.0 0.0 0.0
22808 6 NaN Санкт-Петербург 4529.0 19095.0 0.0 0.0 0.0 0.0
23590 18 NaN Санкт-Петербург 4529.0 19095.0 0.0 0.0 0.0 0.0
5144 19 19.0 Санкт-Петербург 4530.0 18941.0 0.0 0.0 0.0 0.0
18701 19 19.0 Санкт-Петербург 4579.0 18995.0 0.0 0.0 0.0 0.0
19964 4 19.0 Санкт-Петербург 4579.0 18995.0 0.0 0.0 0.0 0.0
22105 19 19.0 Санкт-Петербург 4579.0 18995.0 0.0 0.0 0.0 0.0
22172 17 19.0 Санкт-Петербург 4579.0 18995.0 0.0 0.0 0.0 0.0
13354 19 19.0 Санкт-Петербург 4588.0 18995.0 0.0 0.0 0.0 0.0

Заменим отсутствующее значение на значение 19.

In [214]:
data.loc[data['floors_total'].isna() &
         (data['city_centers_nearest'] == 4529) &
         (data['airports_nearest'] == 19095),
         'floors_total'] = data['floors_total'].fillna(19)

data[columns][(data['city_centers_nearest'] == 4529) &
              (data['airports_nearest'] == 19095)]
Out[214]:
floor floors_total locality_name city_centers_nearest airports_nearest parks_around_3000 parks_nearest ponds_around_3000 ponds_nearest
18832 6 19.0 Санкт-Петербург 4529.0 19095.0 0.0 0.0 0.0 0.0
22808 6 19.0 Санкт-Петербург 4529.0 19095.0 0.0 0.0 0.0 0.0
23590 18 19.0 Санкт-Петербург 4529.0 19095.0 0.0 0.0 0.0 0.0

Выясним, какова этажность зданий в Санкт-Петербурге, расположенных от центра города на расстоянии 14 674 м и от аэропорта на расстоянии 35 234 м, этажность которых составляет не менее 24 этажей.

In [215]:
data[columns][(data['city_centers_nearest'] > 14600) &
              (data['city_centers_nearest'] < 14800) &
              (data['airports_nearest'] > 35100) &
              (data['airports_nearest'] < 35300) &
              (data['floors_total'] >= 24) &
              (data['ponds_around_3000'] == 1)] \
              .sort_values('city_centers_nearest')
Out[215]:
floor floors_total locality_name city_centers_nearest airports_nearest parks_around_3000 parks_nearest ponds_around_3000 ponds_nearest
4758 3 25.0 Санкт-Петербург 14772.0 35257.0 0.0 0.0 1.0 865.0
16888 19 25.0 Санкт-Петербург 14772.0 35257.0 0.0 0.0 1.0 865.0
17232 11 25.0 Санкт-Петербург 14772.0 35257.0 0.0 0.0 1.0 865.0
19206 19 24.0 Санкт-Петербург 14772.0 35257.0 0.0 0.0 1.0 865.0
19293 12 25.0 Санкт-Петербург 14772.0 35257.0 0.0 0.0 1.0 865.0
22050 11 25.0 Санкт-Петербург 14772.0 35257.0 0.0 0.0 1.0 865.0

Заменим отсутствующее значение на значение моды — 25.

In [216]:
data.loc[data['floors_total'].isna() &
         (data['city_centers_nearest'] == 14674) &
         (data['airports_nearest'] == 35234),
         'floors_total'] = data['floors_total'].fillna(25)

data[columns][(data['city_centers_nearest'] == 14674) &
              (data['airports_nearest'] == 35234)]
Out[216]:
floor floors_total locality_name city_centers_nearest airports_nearest parks_around_3000 parks_nearest ponds_around_3000 ponds_nearest
6030 24 25.0 Санкт-Петербург 14674.0 35234.0 0.0 0.0 1.0 844.0
11389 7 25.0 Санкт-Петербург 14674.0 35234.0 0.0 0.0 1.0 844.0
13622 21 25.0 Санкт-Петербург 14674.0 35234.0 0.0 0.0 1.0 844.0
21273 19 25.0 Санкт-Петербург 14674.0 35234.0 0.0 0.0 1.0 844.0

Выясним, какова этажность зданий в Санкт-Петербурге, расположенных от центра города на расстоянии 18 535 м и от аэропорта на расстоянии 19 533 м, вокруг которых есть 1 парк, но нет водоёмов.

In [217]:
data[columns][(data['city_centers_nearest'] > 18500) &
              (data['city_centers_nearest'] < 18600) &
              (data['airports_nearest'] > 19500) &
              (data['airports_nearest'] < 19600) &
              (data['parks_around_3000'] == 1) &
              (data['ponds_around_3000'] == 0)] \
              .sort_values('city_centers_nearest')
Out[217]:
floor floors_total locality_name city_centers_nearest airports_nearest parks_around_3000 parks_nearest ponds_around_3000 ponds_nearest
12565 3 8.0 Санкт-Петербург 18525.0 19523.0 1.0 365.0 0.0 0.0
13989 2 8.0 Санкт-Петербург 18525.0 19523.0 1.0 365.0 0.0 0.0
22252 4 8.0 Санкт-Петербург 18525.0 19523.0 1.0 365.0 0.0 0.0
12399 4 NaN Санкт-Петербург 18535.0 19533.0 1.0 375.0 0.0 0.0
3871 1 8.0 Санкт-Петербург 18583.0 19580.0 1.0 400.0 0.0 0.0

Заменим отсутствующие значения на значение 8.

In [218]:
data.loc[data['floors_total'].isna() &
         (data['city_centers_nearest'] == 18535) &
         (data['airports_nearest'] == 19533),
         'floors_total'] = data['floors_total'].fillna(8)

data[columns][(data['city_centers_nearest'] == 18535) &
              (data['airports_nearest'] == 19533)]
Out[218]:
floor floors_total locality_name city_centers_nearest airports_nearest parks_around_3000 parks_nearest ponds_around_3000 ponds_nearest
12399 4 8.0 Санкт-Петербург 18535.0 19533.0 1.0 375.0 0.0 0.0

Выясним, какова этажность зданий в Мурино, расположенных от центра города на расстоянии 21 888 м и от аэропорта на расстоянии 51 553 м.

In [219]:
data[columns][(data['city_centers_nearest'] > 21000) &
              (data['city_centers_nearest'] < 22500) &
              (data['airports_nearest'] > 51000) &
              (data['airports_nearest'] < 52000)] \
              .sort_values('city_centers_nearest')
Out[219]:
floor floors_total locality_name city_centers_nearest airports_nearest parks_around_3000 parks_nearest ponds_around_3000 ponds_nearest
10259 5 NaN Мурино 21888.0 51553.0 0.0 0.0 2.0 133.0
11425 4 NaN Мурино 21888.0 51553.0 0.0 0.0 2.0 133.0

В наборе данных нет сведений о рядом расположенных зданиях, поэтому заменим отсутствующие значения на максимальное значение признака floors — 5.

In [220]:
data.loc[(data['floors_total'].isna() == True) &
         (data['city_centers_nearest'] == 21888) &
         (data['airports_nearest'] == 51553),
         'floors_total'] = data['floors_total'].fillna(5)

data[columns][(data['city_centers_nearest'] == 21888) &
              (data['airports_nearest'] == 51553)]
Out[220]:
floor floors_total locality_name city_centers_nearest airports_nearest parks_around_3000 parks_nearest ponds_around_3000 ponds_nearest
10259 5 5.0 Мурино 21888.0 51553.0 0.0 0.0 2.0 133.0
11425 4 5.0 Мурино 21888.0 51553.0 0.0 0.0 2.0 133.0

Выясним, какова этажность зданий в Красном Селе, расположенных от центра города на расстоянии 28 806 м и от аэропорта на расстоянии 25 382 м, вокруг которых нет парков и водоёмов.

In [221]:
data[columns][(data['city_centers_nearest'] > 28750) &
              (data['city_centers_nearest'] < 28900) &
              (data['airports_nearest'] > 25000) &
              (data['airports_nearest'] < 25500) &
              (data['parks_around_3000'] == 0)] \
              .sort_values('city_centers_nearest')
Out[221]:
floor floors_total locality_name city_centers_nearest airports_nearest parks_around_3000 parks_nearest ponds_around_3000 ponds_nearest
11488 1 8.0 Красное Село 28765.0 25341.0 0.0 0.0 0.0 0.0
2437 5 8.0 Красное Село 28784.0 25359.0 0.0 0.0 0.0 0.0
6789 3 8.0 Красное Село 28784.0 25359.0 0.0 0.0 0.0 0.0
15989 1 NaN Красное Село 28806.0 25382.0 0.0 0.0 0.0 0.0
1976 7 9.0 Красное Село 28837.0 25413.0 0.0 0.0 0.0 0.0
11276 7 9.0 Красное Село 28837.0 25413.0 0.0 0.0 0.0 0.0
10352 3 8.0 Красное Село 28856.0 25431.0 0.0 0.0 0.0 0.0

Заменим отсутствующее значение на значение моды — 8.

In [222]:
data.loc[data['floors_total'].isna() &
         (data['city_centers_nearest'] == 28806) &
         (data['airports_nearest'] == 25382),
         'floors_total'] = data['floors_total'].fillna(8)

data[columns][(data['city_centers_nearest'] == 28806) &
              (data['airports_nearest'] == 25382)]
Out[222]:
floor floors_total locality_name city_centers_nearest airports_nearest parks_around_3000 parks_nearest ponds_around_3000 ponds_nearest
15989 1 8.0 Красное Село 28806.0 25382.0 0.0 0.0 0.0 0.0

Выясним, какова этажность зданий в Пушкине, расположенных от центра города на расстоянии 31 813 м и от аэропорта на расстоянии 19 659 м.

In [223]:
data[columns][(data['city_centers_nearest'] > 31500) &
              (data['city_centers_nearest'] < 32000) &
              (data['airports_nearest'] > 19500) &
              (data['airports_nearest'] < 20000) &
              (data['locality_name'] == 'Пушкин')] \
              .sort_values('city_centers_nearest')
Out[223]:
floor floors_total locality_name city_centers_nearest airports_nearest parks_around_3000 parks_nearest ponds_around_3000 ponds_nearest
2526 4 5.0 Пушкин 31725.0 19571.0 0.0 0.0 0.0 0.0
8986 4 NaN Пушкин 31813.0 19659.0 0.0 0.0 0.0 0.0
21119 2 4.0 Пушкин 31897.0 19744.0 0.0 0.0 0.0 0.0
17874 3 3.0 Пушкин 31914.0 19760.0 0.0 0.0 0.0 0.0

Поскольку все найденные значения разные, заполним отсутствующее значение медианным значением — 4.

In [224]:
data.loc[data['floors_total'].isna() &
         (data['city_centers_nearest'] == 31813) &
         (data['airports_nearest'] == 19659),
         'floors_total'] = data['floors_total'].fillna(4)

data[columns][(data['city_centers_nearest'] == 31813) &
              (data['airports_nearest'] == 19659)]
Out[224]:
floor floors_total locality_name city_centers_nearest airports_nearest parks_around_3000 parks_nearest ponds_around_3000 ponds_nearest
8986 4 4.0 Пушкин 31813.0 19659.0 0.0 0.0 0.0 0.0

Выясним, какова этажность зданий в Щеглово, расположенных от центра города на расстоянии 34 085 м и от аэропорта на расстоянии 61 908 м.

In [225]:
data[columns][(data['city_centers_nearest'] > 33500) &
              (data['city_centers_nearest'] < 34500) &
              (data['airports_nearest'] > 61500) &
              (data['airports_nearest'] < 62300)] \
              .sort_values('city_centers_nearest')
Out[225]:
floor floors_total locality_name city_centers_nearest airports_nearest parks_around_3000 parks_nearest ponds_around_3000 ponds_nearest
3817 1 NaN Щеглово 34085.0 61908.0 0.0 0.0 0.0 0.0

В наборе данных нет сведений о рядом расположенных зданиях, поэтому заменим отсутствующее значение на моду значений этажности зданий, расположенных в Щеглово.

In [226]:
data.loc[data['locality_name'] == 'Щеглово', 'floors_total'].mode()
Out[226]:
0    4.0
Name: floors_total, dtype: float64

Заменим отсутствующее значение на 4.

In [227]:
data.loc[data['floors_total'].isna() &
         (data['city_centers_nearest'] == 34085) &
         (data['airports_nearest'] == 61908),
         'floors_total'] = data['floors_total'].fillna(4)

data[columns][(data['city_centers_nearest'] == 34085) &
              (data['airports_nearest'] == 61908)]
Out[227]:
floor floors_total locality_name city_centers_nearest airports_nearest parks_around_3000 parks_nearest ponds_around_3000 ponds_nearest
3817 1 4.0 Щеглово 34085.0 61908.0 0.0 0.0 0.0 0.0

Оставшиеся 10 записей, в которых отсутствует значение признака floors_total, не представляется возможным заполнить, поскольку в них наблюдается большое количество пропущенных значений, а из картографических данных имеется только название населённого пункта.

In [228]:
data[columns][data['floors_total'].isna()]
Out[228]:
floor floors_total locality_name city_centers_nearest airports_nearest parks_around_3000 parks_nearest ponds_around_3000 ponds_nearest
3031 12 NaN Кудрово NaN NaN NaN NaN NaN NaN
3438 12 NaN Кудрово NaN NaN NaN NaN NaN NaN
3831 7 NaN Санкт-Петербург NaN NaN NaN NaN NaN NaN
4901 6 NaN Бугры NaN NaN NaN NaN NaN NaN
5187 15 NaN Мурино NaN NaN NaN NaN NaN NaN
9023 11 NaN Новоселье NaN NaN NaN NaN NaN NaN
10058 21 NaN Шушары NaN NaN NaN NaN NaN NaN
10351 4 NaN Токсово NaN NaN NaN NaN NaN NaN
14094 17 NaN Новое Девяткино NaN NaN NaN NaN NaN NaN
20738 10 NaN Мурино NaN NaN NaN NaN NaN NaN

Поэтому эти записи необходимо удалить.

In [229]:
data.drop(index=data[data['floors_total'].isna()].index, inplace=True)
In [230]:
show_na()
Всего пропусков %
ceiling_height 9092 38.8
ponds_nearest 5421 23.1
ponds_around_3000 5421 23.1
parks_nearest 5421 23.1
parks_around_3000 5421 23.1
city_centers_nearest 5421 23.1
airports_nearest 5421 23.1
days_exposition 3153 13.4
kitchen_area 2254 9.6
living_area 1896 8.1
total_images 0 0.0
balcony 0 0.0
locality_name 0 0.0
open_plan 0 0.0
last_price 0 0.0
studio 0 0.0
is_apartment 0 0.0
floor 0 0.0
floors_total 0 0.0
rooms 0 0.0
first_day_exposition 0 0.0
total_area 0 0.0
locality_type 0 0.0

Высота потолков¶

Почти 40 % значений признака ceiling_height содержат пропуски.

Поскольку большая часть зданий, в которых расположены объекты недвижимости, вероятно, представляют собой дома типовой застройки, высота потолков представляется такой же "типовой" величиной. На эти значения влияют толщина напольного и потолочного покрытий. Но, во-первых, далеко не во всех квартирах есть натяжной/подвесной потолок (сильно уменьшающий высоту потолков), а во-вторых, значение высоты потолка в объявлении могут указывать в соответствии с официальным планом квартиры, а не специально измеряют её для публикации объявления. Кроме того, можно полагать, что вероятность встретить в одном населённом пункте дома, принадлежащие к одному типу, выше, чем в разных населённых пунктах. Таким образом, наличие популярного значения (моды) в значении высоты потолка для зданий определённой этажности в каждом населённом пункте может расцениваться как типовое значение высоты потолка.

Поэтому будем заполнять пропуски модой, рассчитанной для зданий определённой этажности в каждом населённом пункте. В случае, когда в выборках присутствует более одной моды, будем заполнять пропуски медианным значением, которое зачастую расположено между значениями мод, и таким образом является средним ещё и для мод.

In [231]:
for locality in list(data.loc[data['ceiling_height'].isna(),
                              'locality_name'].unique()):
    for floors in list(data.loc[data['ceiling_height'].isna() &
                                (data['locality_name'] == locality),
                                'floors_total'].unique()):

        mode_value = data[data['ceiling_height'].notna() &
                          (data['locality_name'] == locality) &
                          (data['floors_total'] == floors)]['ceiling_height'].mode()

        median_value = data[data['ceiling_height'].notna() &
                            (data['locality_name'] == locality) &
                            (data['floors_total'] == floors)]['ceiling_height'].median()

        if len(mode_value) == 1:
            data.loc[data['ceiling_height'].isna() &
                     (data['locality_name'] == locality) &
                     (data['floors_total'] == floors),
                     'ceiling_height'] = mode_value[0]

        elif len(mode_value) != 1:
            data.loc[data['ceiling_height'].isna() &
                     (data['locality_name'] == locality) &
                     (data['floors_total'] == floors),
                     'ceiling_height'] = median_value
In [232]:
data['ceiling_height'].sort_values().unique()
Out[232]:
array([2.   , 2.25 , 2.26 , 2.3  , 2.34 , 2.4  , 2.45 , 2.46 , 2.47 ,
       2.48 , 2.49 , 2.5  , 2.51 , 2.52 , 2.525, 2.53 , 2.54 , 2.55 ,
       2.56 , 2.57 , 2.575, 2.58 , 2.59 , 2.6  , 2.61 , 2.615, 2.62 ,
       2.625, 2.63 , 2.64 , 2.65 , 2.65 , 2.66 , 2.67 , 2.675, 2.68 ,
       2.69 , 2.7  , 2.71 , 2.72 , 2.725, 2.73 , 2.74 , 2.75 , 2.76 ,
       2.77 , 2.775, 2.775, 2.78 , 2.79 , 2.8  , 2.81 , 2.82 , 2.83 ,
       2.84 , 2.85 , 2.86 , 2.87 , 2.88 , 2.89 , 2.9  , 2.91 , 2.92 ,
       2.93 , 2.94 , 2.95 , 2.96 , 2.97 , 2.98 , 2.99 , 3.   , 3.01 ,
       3.02 , 3.03 , 3.04 , 3.05 , 3.06 , 3.07 , 3.08 , 3.09 , 3.1  ,
       3.11 , 3.12 , 3.13 , 3.14 , 3.15 , 3.16 , 3.17 , 3.18 , 3.2  ,
       3.21 , 3.22 , 3.23 , 3.24 , 3.25 , 3.26 , 3.27 , 3.28 , 3.29 ,
       3.3  , 3.31 , 3.32 , 3.325, 3.33 , 3.34 , 3.35 , 3.36 , 3.37 ,
       3.38 , 3.39 , 3.4  , 3.42 , 3.43 , 3.44 , 3.45 , 3.46 , 3.47 ,
       3.48 , 3.49 , 3.5  , 3.51 , 3.52 , 3.53 , 3.54 , 3.55 , 3.56 ,
       3.57 , 3.58 , 3.59 , 3.6  , 3.62 , 3.63 , 3.65 , 3.66 , 3.67 ,
       3.68 , 3.69 , 3.7  , 3.75 , 3.76 , 3.78 , 3.8  , 3.82 , 3.83 ,
       3.84 , 3.85 , 3.86 , 3.87 , 3.88 , 3.9  , 3.93 , 3.95 , 3.98 ,
       4.   , 4.06 , 4.1  , 4.14 , 4.15 , 4.19 , 4.2  , 4.25 , 4.3  ,
       4.37 , 4.4  , 4.45 , 4.5  , 4.65 , 4.7  , 4.8  , 4.9  , 5.   ,
       5.2  , 5.3  , 5.5  , 5.6  , 5.8  , 6.   ,   nan])

Выясним, сколько осталось записей, содержащих пропуски в значениях признака ceiling_height.

In [233]:
data['ceiling_height'].isna().sum()
Out[233]:
314

Среди записей, в которых отсутствует значение высоты потолка, нет объектов недвижимости, расположенных в Санкт-Петербурге.

In [234]:
len(data[data['ceiling_height'].isna() &
         (data['locality_name'] == 'Санкт-Петербург')])
Out[234]:
0

Распределение значений высоты потолка объектов недвижимости, расположенных в Санкт-Петербурге, отличается от распределения значений высоты потолка объектов недвижимости в Ленинградской области. Отличаются и значения мод. Вероятно, такое распределение величины является следствием того, что область преимущественно застраивалась типовыми зданиями, а в Санкт-Петербурге расположено большое количество зданий более ранней постройки.

Поэтому заполним отсутствующие значения модой, рассчитанной для зданий определённой этажности, расположенных в Ленинградской области. А в случае, если таких мод несколько, то медианным значением.

In [235]:
for floors in list(data.loc[data['ceiling_height'].isna() &
                            (data['locality_name'] != 'Санкт-Петербург'),
                            'floors_total'].unique()):

        mode_value = data[data['ceiling_height'].notna() &
                          (data['floors_total'] == floors)]['ceiling_height'].mode()

        median_value = data[data['ceiling_height'].notna() &
                            (data['floors_total'] == floors)]['ceiling_height'].median()

        if len(mode_value) == 1:
            data.loc[data['ceiling_height'].isna() &
                     (data['floors_total'] == floors),
                     'ceiling_height'] = mode_value[0]

        elif len(mode_value) != 1:
            data.loc[data['ceiling_height'].isna() &
                     (data['floors_total'] == floors),
                     'ceiling_height'] = median_value
In [236]:
data['ceiling_height'].sort_values().unique()
Out[236]:
array([2.   , 2.25 , 2.26 , 2.3  , 2.34 , 2.4  , 2.45 , 2.46 , 2.47 ,
       2.48 , 2.49 , 2.5  , 2.51 , 2.52 , 2.525, 2.53 , 2.54 , 2.55 ,
       2.56 , 2.57 , 2.575, 2.58 , 2.59 , 2.6  , 2.61 , 2.615, 2.62 ,
       2.625, 2.63 , 2.64 , 2.65 , 2.65 , 2.66 , 2.67 , 2.675, 2.68 ,
       2.69 , 2.7  , 2.71 , 2.72 , 2.725, 2.73 , 2.74 , 2.75 , 2.76 ,
       2.77 , 2.775, 2.775, 2.78 , 2.79 , 2.8  , 2.81 , 2.82 , 2.83 ,
       2.84 , 2.85 , 2.86 , 2.87 , 2.88 , 2.89 , 2.9  , 2.91 , 2.92 ,
       2.93 , 2.94 , 2.95 , 2.96 , 2.97 , 2.98 , 2.99 , 3.   , 3.01 ,
       3.02 , 3.03 , 3.04 , 3.05 , 3.06 , 3.07 , 3.08 , 3.09 , 3.1  ,
       3.11 , 3.12 , 3.13 , 3.14 , 3.15 , 3.16 , 3.17 , 3.18 , 3.2  ,
       3.21 , 3.22 , 3.23 , 3.24 , 3.25 , 3.26 , 3.27 , 3.28 , 3.29 ,
       3.3  , 3.31 , 3.32 , 3.325, 3.33 , 3.34 , 3.35 , 3.36 , 3.37 ,
       3.38 , 3.39 , 3.4  , 3.42 , 3.43 , 3.44 , 3.45 , 3.46 , 3.47 ,
       3.48 , 3.49 , 3.5  , 3.51 , 3.52 , 3.53 , 3.54 , 3.55 , 3.56 ,
       3.57 , 3.58 , 3.59 , 3.6  , 3.62 , 3.63 , 3.65 , 3.66 , 3.67 ,
       3.68 , 3.69 , 3.7  , 3.75 , 3.76 , 3.78 , 3.8  , 3.82 , 3.83 ,
       3.84 , 3.85 , 3.86 , 3.87 , 3.88 , 3.9  , 3.93 , 3.95 , 3.98 ,
       4.   , 4.06 , 4.1  , 4.14 , 4.15 , 4.19 , 4.2  , 4.25 , 4.3  ,
       4.37 , 4.4  , 4.45 , 4.5  , 4.65 , 4.7  , 4.8  , 4.9  , 5.   ,
       5.2  , 5.3  , 5.5  , 5.6  , 5.8  , 6.   ])

Все значения высоты потолков расположены в установленном диапазоне 2—6 м. Пропуски все заполнены.

In [237]:
show_na()
Всего пропусков %
ponds_nearest 5421 23.1
ponds_around_3000 5421 23.1
parks_nearest 5421 23.1
parks_around_3000 5421 23.1
city_centers_nearest 5421 23.1
airports_nearest 5421 23.1
days_exposition 3153 13.4
kitchen_area 2254 9.6
living_area 1896 8.1
total_images 0 0.0
locality_name 0 0.0
balcony 0 0.0
open_plan 0 0.0
last_price 0 0.0
studio 0 0.0
is_apartment 0 0.0
floor 0 0.0
floors_total 0 0.0
ceiling_height 0 0.0
rooms 0 0.0
first_day_exposition 0 0.0
total_area 0 0.0
locality_type 0 0.0

Поскольку опубликованные в объявлениях значения высоты потолка были определены с точностью до 0,01 м, то все рассчитанные значения должны быть округлены с точностью до 0,01 м.

In [238]:
data['ceiling_height'] = data['ceiling_height'].round(2)
In [239]:
data['ceiling_height'].sort_values().unique()
Out[239]:
array([2.  , 2.25, 2.26, 2.3 , 2.34, 2.4 , 2.45, 2.46, 2.47, 2.48, 2.49,
       2.5 , 2.51, 2.52, 2.53, 2.54, 2.55, 2.56, 2.57, 2.58, 2.59, 2.6 ,
       2.61, 2.62, 2.63, 2.64, 2.65, 2.66, 2.67, 2.68, 2.69, 2.7 , 2.71,
       2.72, 2.73, 2.74, 2.75, 2.76, 2.77, 2.78, 2.79, 2.8 , 2.81, 2.82,
       2.83, 2.84, 2.85, 2.86, 2.87, 2.88, 2.89, 2.9 , 2.91, 2.92, 2.93,
       2.94, 2.95, 2.96, 2.97, 2.98, 2.99, 3.  , 3.01, 3.02, 3.03, 3.04,
       3.05, 3.06, 3.07, 3.08, 3.09, 3.1 , 3.11, 3.12, 3.13, 3.14, 3.15,
       3.16, 3.17, 3.18, 3.2 , 3.21, 3.22, 3.23, 3.24, 3.25, 3.26, 3.27,
       3.28, 3.29, 3.3 , 3.31, 3.32, 3.33, 3.34, 3.35, 3.36, 3.37, 3.38,
       3.39, 3.4 , 3.42, 3.43, 3.44, 3.45, 3.46, 3.47, 3.48, 3.49, 3.5 ,
       3.51, 3.52, 3.53, 3.54, 3.55, 3.56, 3.57, 3.58, 3.59, 3.6 , 3.62,
       3.63, 3.65, 3.66, 3.67, 3.68, 3.69, 3.7 , 3.75, 3.76, 3.78, 3.8 ,
       3.82, 3.83, 3.84, 3.85, 3.86, 3.87, 3.88, 3.9 , 3.93, 3.95, 3.98,
       4.  , 4.06, 4.1 , 4.14, 4.15, 4.19, 4.2 , 4.25, 4.3 , 4.37, 4.4 ,
       4.45, 4.5 , 4.65, 4.7 , 4.8 , 4.9 , 5.  , 5.2 , 5.3 , 5.5 , 5.6 ,
       5.8 , 6.  ])

Жилая площадь и площадь кухни в квартирах-студиях¶

Всего записей о квартирах-студиях с пропущенным значением жилой площади — 13.

In [240]:
len(data[data['studio'] & data['living_area'].isna()])
Out[240]:
13

Заполним пропущенное значение жилой площади средним арифметическим значением, рассчитанным для квартир-студий в каждом населённом пункте, каждого здания определённой этажности и каждой квартиры с определённым числом жилых комнат.

In [241]:
for locality in list(data.loc[data['studio'] &
                              data['living_area'].isna(),
                              'locality_name'].sort_values().unique()):
    for floors in list(data.loc[data['studio'] &
                                data['living_area'].isna() &
                                (data['locality_name'] == locality),
                                'floors_total'].sort_values().unique()):
        for rooms in list(data.loc[data['studio'] &
                                   data['living_area'].isna() &
                                   (data['locality_name'] == locality) &
                                   (data['floors_total'] == floors),
                                   'rooms'].sort_values().unique()):

            mean_value = data.loc[data['studio'] &
                                  data['living_area'].notna() &
                                  (data['locality_name'] == locality) &
                                  (data['floors_total'] == floors) &
                                  (data['rooms'] == rooms), 'living_area'].mean()

            data.loc[data['studio'] &
                     data['living_area'].isna() &
                     (data['locality_name'] == locality) &
                     (data['floors_total'] == floors) &
                     (data['rooms'] == rooms), 'living_area'] = mean_value

Количество записей, для которых не удалось рассчитать среднее значение жилой площади.

In [242]:
len(data[data['studio'] & data['living_area'].isna()])
Out[242]:
5

Заполним пропущенное значение жилой площади средним арифметическим значением, рассчитанным для квартир-студий во всех населённых пунктах, для каждого здания определённой этажности и каждой квартиры с определённым числом жилых комнат.

In [243]:
for floors in list(data.loc[data['studio'] &
                            data['living_area'].isna(),
                            'floors_total'].sort_values().unique()):
    for rooms in list(data.loc[data['studio'] &
                               data['living_area'].isna() &
                               (data['floors_total'] == floors),
                               'rooms'].sort_values().unique()):

        mean_value = data.loc[data['studio'] &
                              data['living_area'].notna() &
                              (data['floors_total'] == floors) &
                              (data['rooms'] == rooms), 'living_area'].mean()

        data.loc[data['studio'] &
                 data['living_area'].isna() &
                 (data['floors_total'] == floors) &
                 (data['rooms'] == rooms), 'living_area'] = mean_value

Количество записей, для которых не удалось рассчитать среднее значение жилой площади.

In [244]:
len(data[data['studio'] & data['living_area'].isna()])
Out[244]:
2

Заполним пропущенное значение жилой площади средним арифметическим значением, рассчитанным для квартир-студий во всех населённых пунктах, в зданиях любой этажности, но для каждой квартиры с определённым числом жилых комнат.

In [245]:
for rooms in list(data.loc[data['studio'] &
                           data['living_area'].isna(),
                           'rooms'].sort_values().unique()):

    mean_value = data.loc[data['living_area'].notna() &
                          (data['rooms'] == rooms), 'living_area'].mean()

    data.loc[data['studio'] &
             data['living_area'].isna() &
             (data['rooms'] == rooms), 'living_area'] = mean_value

Количество записей, не удовлетворяющих критерию, что минимальная площадь, приходящаяся на вспомогательные помещения (кроме кухни) составляет 2 м².

In [246]:
len(data[data['total_area'] < data['living_area'] + 2])
Out[246]:
0

Всего записей о квартирах-студиях с пропущенным значением площади кухни — 211.

In [247]:
len(data[data['studio'] & data['kitchen_area'].isna()])
Out[247]:
211

Поскольку в таких квартирах часто кухня выполнена в виде кухни-нишы, а однокомнатных квартир-студий — подавляющее количество среди всех студий, будем полагать, что площадь, отводимая на зону кухни-ниши, составляет 15 % от общей площади. Тем более, что это близко к среднему значению по всему набору данных — 19 % от общей площади приходится на площадь кухни.

In [248]:
(data['kitchen_area']/data['total_area']).mean().round(2)
Out[248]:
0.19
In [249]:
data.loc[data['studio'], 'kitchen_area'] = 0.15 * data['total_area']
In [250]:
show_na()
Всего пропусков %
ponds_nearest 5421 23.1
ponds_around_3000 5421 23.1
parks_nearest 5421 23.1
parks_around_3000 5421 23.1
city_centers_nearest 5421 23.1
airports_nearest 5421 23.1
days_exposition 3153 13.4
kitchen_area 2043 8.7
living_area 1883 8.0
total_images 0 0.0
locality_name 0 0.0
balcony 0 0.0
open_plan 0 0.0
last_price 0 0.0
studio 0 0.0
is_apartment 0 0.0
floor 0 0.0
floors_total 0 0.0
ceiling_height 0 0.0
rooms 0 0.0
first_day_exposition 0 0.0
total_area 0 0.0
locality_type 0 0.0

Жилая площадь и площадь кухни¶

Пропущенных значений признака kitchen_area больше, чем признака living_area. Количество пропусков приблизительно равно 10 % в каждом признаке.

Количество записей, в которых указана жилая площадь, но не указана площадь кухни — 599.

In [251]:
len(data[~data['studio'] &
         data['living_area'].notna() &
         data['kitchen_area'].isna()])
Out[251]:
599

Все эти объекты недвижимости расположены в 59 различных населённых пунктах.

In [252]:
len(data.loc[~data['studio'] &
             data['living_area'].notna() &
             data['kitchen_area'].isna(), 'locality_name'].unique())
Out[252]:
59

Поскольку значение площади кухни есть величина непрерывная и вариативная, в качестве оценки среднего значения примем среднее арифметическое. В каждом населённом пункте для домов определённой этажности рассчитаем среднее значение площади кухни для каждого типа квартир (1-комн., 2-комн. и т. д.). Заполним отсутствующие значения площади кухни средним арифметическим, рассчитанным в соответствии с количеством комнат в квартире, этажностью здания, в котором располагается объект недвижимости, и населённым пунктом, где располагается здание.

In [253]:
for locality in list(data.loc[~data['studio'] &
                              data['kitchen_area'].isna() &
                              data['living_area'].notna(),
                              'locality_name'].sort_values().unique()):
    for floors in list(data.loc[~data['studio'] &
                                data['kitchen_area'].isna() &
                                data['living_area'].notna() &
                                (data['locality_name'] == locality),
                                'floors_total'].sort_values().unique()):
        for rooms in list(data.loc[~data['studio'] &
                                   data['kitchen_area'].isna() &
                                   data['living_area'].notna() &
                                   (data['locality_name'] == locality) &
                                   (data['floors_total'] == floors),
                                   'rooms'].sort_values().unique()):

            mean_value = data.loc[~data['studio'] &
                                  data['kitchen_area'].notna() &
                                  data['living_area'].notna() &
                                  (data['locality_name'] == locality) &
                                  (data['floors_total'] == floors) &
                                  (data['rooms'] == rooms),
                                  'kitchen_area'].mean()

            data.loc[~data['studio'] &
                     data['kitchen_area'].isna() &
                     data['living_area'].notna() &
                     (data['locality_name'] == locality) &
                     (data['floors_total'] == floors) &
                     (data['rooms'] == rooms), 'kitchen_area'] = mean_value

Количество записей, для которых не удалось рассчитать среднее значение площади кухни.

In [254]:
len(data[~data['studio'] &
         data['living_area'].notna() &
         data['kitchen_area'].isna()])
Out[254]:
19

Количество записей, для которых не выполняется критерий, что площадь вспомогательных помещений (кроме кухни) должна составлять не менее 2 м².

In [255]:
len(data[~data['studio'] &
         (data['total_area'] < data['living_area'] + data['kitchen_area'] + 2)])
Out[255]:
161

Заменим в таких записях полученное значение площади кухни значением NaN.

In [256]:
data.loc[~data['studio'] &
         (data['total_area'] < data['living_area'] + data['kitchen_area'] + 2),
         'kitchen_area'] = 0
data['kitchen_area'].replace(0, np.nan, inplace=True)

len(data[~data['studio'] &
         data['living_area'].notna() &
         data['kitchen_area'].isna()])
Out[256]:
180

Рассчитаем теперь для каждого населенного пункта минимальное значение площади кухни для схожих объектов недвижимости: расположенных в квартирах такой же комнатности, зданиях такой же этажности, в том же населённом пункте.

In [257]:
for locality in list(data.loc[~data['studio'] &
                              data['kitchen_area'].isna() &
                              data['living_area'].notna(),
                              'locality_name'].sort_values().unique()):
    for floors in list(data.loc[~data['studio'] &
                                data['kitchen_area'].isna() &
                                data['living_area'].notna() &
                                (data['locality_name'] == locality),
                                'floors_total'].sort_values().unique()):
        for rooms in list(data.loc[~data['studio'] &
                                   data['kitchen_area'].isna() &
                                   data['living_area'].notna() &
                                   (data['locality_name'] == locality) &
                                   (data['floors_total'] == floors),
                                   'rooms'].sort_values().unique()):

            min_value = data.loc[~data['studio'] &
                                 data['kitchen_area'].notna() &
                                 data['living_area'].notna() &
                                 (data['locality_name'] == locality) &
                                 (data['floors_total'] == floors) &
                                 (data['rooms'] == rooms), 'kitchen_area'].min()

            data.loc[~data['studio'] &
                     data['kitchen_area'].isna() &
                     data['living_area'].notna() &
                     (data['locality_name'] == locality) &
                     (data['floors_total'] == floors) &
                     (data['rooms'] == rooms), 'kitchen_area'] = min_value

Теперь количество записей, не удовлетворяющих критерию, уменьшилось.

In [258]:
len(data[~data['studio'] &
         (data['total_area'] < data['living_area'] + data['kitchen_area'] + 2)])
Out[258]:
75

Заменим в таких записях полученное значение площади кухни значением NaN.

In [259]:
data.loc[~data['studio'] &
         (data['total_area'] < data['living_area'] + data['kitchen_area'] + 2),
         'kitchen_area'] = 0
data['kitchen_area'].replace(0, np.nan, inplace=True)

len(data[~data['studio'] &
         data['living_area'].notna() &
         data['kitchen_area'].isna()])
Out[259]:
94

Теперь рассчитаем среднее арифметическое по региону для квартир той же комнатности и зданий той же этажности.

In [260]:
for floors in list(data.loc[~data['studio'] &
                            data['kitchen_area'].isna() &
                            data['living_area'].notna(),
                            'floors_total'].sort_values().unique()):
    for rooms in list(data.loc[~data['studio'] &
                               data['kitchen_area'].isna() &
                               data['living_area'].notna() &
                               (data['floors_total'] == floors),
                               'rooms'].sort_values().unique()):

        mean_value = data.loc[~data['studio'] &
                              data['kitchen_area'].notna() &
                              data['living_area'].notna() &
                              (data['floors_total'] == floors) &
                              (data['rooms'] == rooms), 'kitchen_area'].mean()

        data.loc[~data['studio'] &
                 data['kitchen_area'].isna() &
                 data['living_area'].notna() &
                 (data['floors_total'] == floors) &
                 (data['rooms'] == rooms), 'kitchen_area'] = mean_value

Количество записей, для которых не удалось произвести заполнение средним значением площади кухни.

In [261]:
len(data[~data['studio'] &
         data['living_area'].notna() &
         data['kitchen_area'].isna()])
Out[261]:
1

Количество записей, для которых не выполнен критерий, что площадь вспомогательных помещений (кроме кухни) должна составлять не менее 2 м².

In [262]:
len(data[~data['studio'] &
         (data['total_area'] < data['living_area'] + data['kitchen_area'] + 2)])
Out[262]:
77

Заменим в таких записях полученное значение площади кухни значением NaN.

In [263]:
data.loc[~data['studio'] &
         (data['total_area'] < data['living_area'] + data['kitchen_area'] + 2),
         'kitchen_area'] = 0
data['kitchen_area'].replace(0, np.nan, inplace=True)

len(data[~data['studio'] &
         data['living_area'].notna() &
         data['kitchen_area'].isna()])
Out[263]:
78

Теперь рассчитаем минимальное значение по региону для квартир той же комнатности и зданий той же этажности.

In [264]:
for floors in list(data.loc[~data['studio'] &
                            data['kitchen_area'].isna() &
                            data['living_area'].notna(),
                            'floors_total'].sort_values().unique()):
    for rooms in list(data.loc[~data['studio'] &
                               data['kitchen_area'].isna() &
                               data['living_area'].notna() &
                               (data['floors_total'] == floors),
                               'rooms'].sort_values().unique()):

        min_value = data.loc[~data['studio'] &
                             data['kitchen_area'].notna() &
                             data['living_area'].notna() &
                             (data['floors_total'] == floors) &
                             (data['rooms'] == rooms), 'kitchen_area'].min()

        data.loc[~data['studio'] &
                 data['kitchen_area'].isna() &
                 data['living_area'].notna() &
                 (data['floors_total'] == floors) &
                 (data['rooms'] == rooms), 'kitchen_area'] = min_value

Количество записей, для которых не выполнен критерий, что площадь вспомогательных помещений (кроме кухни) должна составлять не менее 2 м².

In [265]:
len(data[~data['studio'] &
         (data['total_area'] < data['living_area'] + data['kitchen_area'] + 2)])
Out[265]:
34

Заменим в таких записях полученное значение площади кухни значением NaN.

In [266]:
data.loc[~data['studio'] &
         (data['total_area'] < data['living_area'] + data['kitchen_area'] + 2),
         'kitchen_area'] = 0
data['kitchen_area'].replace(0, np.nan, inplace=True)

len(data[~data['studio'] &
         data['living_area'].notna() &
         data['kitchen_area'].isna()])
Out[266]:
35

Теперь рассчитаем среднее по региону для зданий любой этажности, но для квартир той же комнатности.

In [267]:
for rooms in list(data.loc[~data['studio'] &
                           data['kitchen_area'].isna() &
                           data['living_area'].notna(),
                           'rooms'].sort_values().unique()):

    mean_value = data.loc[~data['studio'] &
                          data['kitchen_area'].notna() &
                          data['living_area'].notna() &
                          (data['rooms'] == rooms), 'kitchen_area'].mean()

    data.loc[~data['studio'] &
             data['kitchen_area'].isna() &
             data['living_area'].notna() &
             (data['rooms'] == rooms), 'kitchen_area'] = mean_value

Удалось заполнить значения для всех записей, в которых пропущено значение площади кухни, но имеется значение жилой площади.

In [268]:
len(data[~data['studio'] &
         data['living_area'].notna() & data['kitchen_area'].isna()])
Out[268]:
0

Однако не для всех записей выполняется критерий, что площадь вспомогательных помещений (кроме кухни) должна составлять не менее 2 м².

In [269]:
len(data[~data['studio'] &
         (data['total_area'] < data['living_area'] + data['kitchen_area'] + 2)])
Out[269]:
34

Заменим в таких записях полученное значение площади кухни значением NaN.

In [270]:
data.loc[~data['studio'] &
         (data['total_area'] < data['living_area'] + data['kitchen_area'] + 2),
         'kitchen_area'] = 0
data['kitchen_area'].replace(0, np.nan, inplace=True)

len(data[~data['studio'] &
         data['living_area'].notna() & data['kitchen_area'].isna()])
Out[270]:
34

Теперь рассчитаем минимальное значение по региону для зданий любой этажностей, но для квартир той же комнатности.

In [271]:
for rooms in list(data.loc[~data['studio'] &
                           data['kitchen_area'].isna() &
                           data['living_area'].notna(),
                           'rooms'].sort_values().unique()):

    min_value = data.loc[~data['studio'] &
                         data['kitchen_area'].notna() &
                         data['living_area'].notna() &
                         (data['rooms'] == rooms), 'kitchen_area'].min()

    data.loc[~data['studio'] &
             data['kitchen_area'].isna() &
             data['living_area'].notna() &
             (data['rooms'] == rooms), 'kitchen_area'] = min_value

Убедимся, что критерий (площадь вспомогательных помещений (кроме кухни) должна составлять не менее 2 м²) выполняется для всех записей.

In [272]:
len(data[~data['studio'] &
         (data['total_area'] < data['living_area'] + data['kitchen_area'] + 2)])
Out[272]:
0

Количество записей, в которых указана площадь кухни, но не указана жилая площадь.

In [273]:
len(data[~data['studio'] &
         data['living_area'].isna() &
         data['kitchen_area'].notna()])
Out[273]:
439

Все эти объекты недвижимости расположены в 53 различных населённых пунктах.

In [274]:
len(data.loc[~data['studio'] &
             data['living_area'].isna() &
             data['kitchen_area'].notna(), 'locality_name'].unique())
Out[274]:
53

Заполним средним арифметическим значением жилой площади, рассчитанным по известным значениям жилой площади объектов, расположенных в тех же населённых пунктах, в зданиях той же этажности и с тем же количеством жилых комнат.

In [275]:
for locality in list(data.loc[~data['studio'] &
                              data['kitchen_area'].notna() &
                              data['living_area'].isna(),
                              'locality_name'].sort_values().unique()):
    for floors in list(data.loc[~data['studio'] &
                                data['kitchen_area'].notna() &
                                data['living_area'].isna() &
                                (data['locality_name'] == locality),
                                'floors_total'].sort_values().unique()):
        for rooms in list(data.loc[~data['studio'] &
                                   data['kitchen_area'].notna() &
                                   data['living_area'].isna() &
                                   (data['locality_name'] == locality) &
                                   (data['floors_total'] == floors),
                                   'rooms'].sort_values().unique()):

            mean_value = data.loc[~data['studio'] &
                                  data['kitchen_area'].notna() &
                                  data['living_area'].notna() &
                                  (data['locality_name'] == locality) &
                                  (data['floors_total'] == floors) &
                                  (data['rooms'] == rooms), 'living_area'].mean()

            data.loc[~data['studio'] &
                     data['kitchen_area'].notna() &
                     data['living_area'].isna() &
                     (data['locality_name'] == locality) &
                     (data['floors_total'] == floors) &
                     (data['rooms'] == rooms), 'living_area'] = mean_value

Количество записей, для которых не удалось рассчитать среднее значение жилой площади.

In [276]:
len(data[~data['studio'] &
         data['living_area'].isna() &
         data['kitchen_area'].notna()])
Out[276]:
34

Количество записей, для которых не выполняется критерий, что площадь вспомогательных помещений (кроме кухни) должна составлять не менее 2 м².

In [277]:
len(data[~data['studio'] &
         (data['total_area'] < data['living_area'] + data['kitchen_area'] + 2)])
Out[277]:
19

Заменим в таких записях полученное значение жилой площади значением NaN.

In [278]:
data.loc[~data['studio'] &
         (data['total_area'] < data['living_area'] + data['kitchen_area'] + 2),
         'living_area'] = 0
data['living_area'].replace(0, np.nan, inplace=True)

len(data[~data['studio'] &
         data['living_area'].isna() &
         data['kitchen_area'].notna()])
Out[278]:
53

Заполним минимальным значением жилой площади, рассчитанным по известным значениям жилой площади объектов, расположенных в тех же населённых пунктах, в зданиях той же этажности и с тем же количеством жилых комнат.

In [279]:
for locality in list(data.loc[~data['studio'] &
                              data['kitchen_area'].notna() &
                              data['living_area'].isna(),
                              'locality_name'].sort_values().unique()):
    for floors in list(data.loc[~data['studio'] &
                                data['kitchen_area'].notna() &
                                data['living_area'].isna() &
                                (data['locality_name'] == locality),
                                'floors_total'].sort_values().unique()):
        for rooms in list(data.loc[~data['studio'] &
                                   data['kitchen_area'].notna() &
                                   data['living_area'].isna() &
                                   (data['locality_name'] == locality) &
                                   (data['floors_total'] == floors),
                                   'rooms'].sort_values().unique()):

            min_value = data.loc[~data['studio'] &
                                 data['kitchen_area'].notna() &
                                 data['living_area'].notna() &
                                 (data['locality_name'] == locality) &
                                 (data['floors_total'] == floors) &
                                 (data['rooms'] == rooms), 'living_area'].min()

            data.loc[~data['studio'] &
                     data['kitchen_area'].notna() &
                     data['living_area'].isna() &
                     (data['locality_name'] == locality) &
                     (data['floors_total'] == floors) &
                     (data['rooms'] == rooms), 'living_area'] = min_value

Количество записей, для которых не выполняется критерий, что площадь вспомогательных помещений (кроме кухни) должна составлять не менее 2 м².

In [280]:
len(data[~data['studio'] &
         (data['total_area'] < data['living_area'] + data['kitchen_area'] + 2)])
Out[280]:
5

Заменим в таких записях полученное значение жилой площади значением NaN.

In [281]:
data.loc[~data['studio'] &
         (data['total_area'] < data['living_area'] + data['kitchen_area'] + 2),
         'living_area'] = 0
data['living_area'].replace(0, np.nan, inplace=True)

len(data[~data['studio'] &
         data['living_area'].isna() &
         data['kitchen_area'].notna()])
Out[281]:
39

Заполним средним арифметическим значением жилой площади, рассчитанным по известным значениям жилой площади объектов, расположенных во всех населённых пунктах, но в зданиях той же этажности и с тем же количеством жилых комнат.

In [282]:
for floors in list(data.loc[~data['studio'] &
                            data['kitchen_area'].notna() &
                            data['living_area'].isna(),
                            'floors_total'].sort_values().unique()):
    for rooms in list(data.loc[~data['studio'] &
                               data['kitchen_area'].notna() &
                               data['living_area'].isna() &
                               (data['floors_total'] == floors),
                               'rooms'].sort_values().unique()):

        mean_value = data.loc[~data['studio'] &
                              data['kitchen_area'].notna() &
                              data['living_area'].notna() &
                              (data['floors_total'] == floors) &
                              (data['rooms'] == rooms), 'living_area'].mean()

        data.loc[~data['studio'] &
                 data['kitchen_area'].notna() &
                 data['living_area'].isna() &
                 (data['floors_total'] == floors) &
                 (data['rooms'] == rooms), 'living_area'] = mean_value

Количество записей, для которых не удалось рассчитать среднее значение жилой площади.

In [283]:
len(data[~data['studio'] &
         data['living_area'].isna() & data['kitchen_area'].notna()])
Out[283]:
0

Количество записей, для которых не выполняется критерий, что площадь вспомогательных помещений (кроме кухни) должна составлять не менее 2 м².

In [284]:
len(data[~data['studio'] &
         (data['total_area'] < data['living_area'] + data['kitchen_area'] + 2)])
Out[284]:
6

Заменим в таких записях полученное значение жилой площади значением NaN.

In [285]:
data.loc[~data['studio'] &
         (data['total_area'] < data['living_area'] + data['kitchen_area'] + 2),
         'living_area'] = 0
data['living_area'].replace(0, np.nan, inplace=True)

len(data[~data['studio'] &
         data['living_area'].isna() &
         data['kitchen_area'].notna()])
Out[285]:
6

Заполним минимальным значением жилой площади, рассчитанным по известным значениям жилой площади объектов, расположенных во всех населённых пунктах, но в зданиях той же этажности и с тем же количеством жилых комнат.

In [286]:
for floors in list(data.loc[~data['studio'] &
                            data['kitchen_area'].notna() &
                            data['living_area'].isna(),
                            'floors_total'].sort_values().unique()):
    for rooms in list(data.loc[~data['studio'] &
                               data['kitchen_area'].notna() &
                               data['living_area'].isna() &
                               (data['floors_total'] == floors),
                               'rooms'].sort_values().unique()):

        min_value = data.loc[~data['studio'] &
                             data['kitchen_area'].notna() &
                             data['living_area'].notna() &
                             (data['floors_total'] == floors) &
                             (data['rooms'] == rooms), 'living_area'].min()

        data.loc[~data['studio'] &
                 data['kitchen_area'].notna() &
                 data['living_area'].isna() &
                 (data['floors_total'] == floors) &
                 (data['rooms'] == rooms), 'living_area'] = min_value

Количество записей, для которых не выполняется критерий, что площадь вспомогательных помещений (кроме кухни) должна составлять не менее 2 м².

In [287]:
len(data[~data['studio'] &
         (data['total_area'] < data['living_area'] + data['kitchen_area'] + 2)])
Out[287]:
0
In [288]:
show_na()
Всего пропусков %
ponds_nearest 5421 23.1
ponds_around_3000 5421 23.1
parks_nearest 5421 23.1
parks_around_3000 5421 23.1
city_centers_nearest 5421 23.1
airports_nearest 5421 23.1
days_exposition 3153 13.4
kitchen_area 1444 6.2
living_area 1444 6.2
total_images 0 0.0
locality_name 0 0.0
balcony 0 0.0
open_plan 0 0.0
last_price 0 0.0
studio 0 0.0
is_apartment 0 0.0
floor 0 0.0
floors_total 0 0.0
ceiling_height 0 0.0
rooms 0 0.0
first_day_exposition 0 0.0
total_area 0 0.0
locality_type 0 0.0

Количество записей, в которых не указана жилая площадь и не указана площадь кухни.

In [289]:
len(data[~data['studio'] &
         data['living_area'].isna() &
         data['kitchen_area'].isna()])
Out[289]:
1444

Заполним средним арифметическим значением жилой площади, рассчитанным по известным значениям жилой площади объектов, расположенных в тех же населённых пунктах, в зданиях той же этажности и с тем же количеством жилых комнат.
То же самое выполняем и для значений площади кухни.

In [290]:
for locality in list(data.loc[~data['studio'] &
                              data['living_area'].isna(),
                              'locality_name'].sort_values().unique()):
    for floors in list(data.loc[~data['studio'] &
                                data['living_area'].isna() &
                                (data['locality_name'] == locality),
                                'floors_total'].sort_values().unique()):
        for rooms in list(data.loc[~data['studio'] &
                                   data['living_area'].isna() &
                                   (data['locality_name'] == locality) &
                                   (data['floors_total'] == floors),
                                   'rooms'].sort_values().unique()):

            mean_value = data.loc[~data['studio'] &
                                  data['living_area'].notna() &
                                  (data['locality_name'] == locality) &
                                  (data['floors_total'] == floors) &
                                  (data['rooms'] == rooms), 'living_area'].mean()

            data.loc[~data['studio'] &
                     data['living_area'].isna() &
                     (data['locality_name'] == locality) &
                     (data['floors_total'] == floors) &
                     (data['rooms'] == rooms), 'living_area'] = mean_value
In [291]:
for locality in list(data.loc[~data['studio'] &
                              data['kitchen_area'].isna(),
                              'locality_name'].sort_values().unique()):
    for floors in list(data.loc[~data['studio'] &
                                data['kitchen_area'].isna() &
                                (data['locality_name'] == locality),
                                'floors_total'].sort_values().unique()):
        for rooms in list(data.loc[~data['studio'] &
                                   data['kitchen_area'].isna() &
                                   (data['locality_name'] == locality) &
                                   (data['floors_total'] == floors),
                                   'rooms'].sort_values().unique()):

            mean_value = data.loc[~data['studio'] &
                                  data['kitchen_area'].notna() &
                                  (data['locality_name'] == locality) &
                                  (data['floors_total'] == floors) &
                                  (data['rooms'] == rooms), 'kitchen_area'].mean()

            data.loc[~data['studio'] &
                     data['kitchen_area'].isna() &
                     (data['locality_name'] == locality) &
                     (data['floors_total'] == floors) &
                     (data['rooms'] == rooms), 'kitchen_area'] = mean_value

Количество записей, для которых не удалось рассчитать среднее значение жилой площади.

In [292]:
len(data[~data['studio'] &
         data['living_area'].isna() & data['kitchen_area'].isna()])
Out[292]:
103

Количество записей, для которых не выполняется критерий, что площадь вспомогательных помещений (кроме кухни) должна составлять не менее 2 м².

In [293]:
len(data[~data['studio'] &
         (data['total_area'] < data['living_area'] + data['kitchen_area'] + 2)])
Out[293]:
146

Заменим в таких записях полученное значение жилой площади и значение площади кухни значением NaN.

In [294]:
data.loc[~data['studio'] &
         (data['total_area'] < data['living_area'] + data['kitchen_area'] + 2),
         'living_area'] = 0
data.loc[data['living_area'] == 0, 'kitchen_area'] = 0
data['living_area'].replace(0, np.nan, inplace=True)
data['kitchen_area'].replace(0, np.nan, inplace=True)

len(data[~data['studio'] &
         data['living_area'].isna() & data['kitchen_area'].isna()])
Out[294]:
249

Заполним минимальным значением жилой площади, рассчитанным по известным значениям жилой площади объектов, расположенных в тех же населённых пунктах, в зданиях той же этажности и с тем же количеством жилых комнат.
То же самое выполняем и для значений площади кухни.

In [295]:
for locality in list(data.loc[~data['studio'] &
                              data['living_area'].isna(),
                              'locality_name'].sort_values().unique()):
    for floors in list(data.loc[~data['studio'] &
                                data['living_area'].isna() &
                                (data['locality_name'] == locality),
                                'floors_total'].sort_values().unique()):
        for rooms in list(data.loc[~data['studio'] &
                                   data['living_area'].isna() &
                                   (data['locality_name'] == locality) &
                                   (data['floors_total'] == floors),
                                   'rooms'].sort_values().unique()):

            min_value = data.loc[~data['studio'] &
                                 data['living_area'].notna() &
                                 (data['locality_name'] == locality) &
                                 (data['floors_total'] == floors) &
                                 (data['rooms'] == rooms), 'living_area'].min()

            data.loc[~data['studio'] &
                     data['living_area'].isna() &
                     (data['locality_name'] == locality) &
                     (data['floors_total'] == floors) &
                     (data['rooms'] == rooms), 'living_area'] = min_value
In [296]:
for locality in list(data.loc[~data['studio'] &
                              data['kitchen_area'].isna(),
                              'locality_name'].sort_values().unique()):
    for floors in list(data.loc[~data['studio'] &
                                data['kitchen_area'].isna() &
                                (data['locality_name'] == locality),
                                'floors_total'].sort_values().unique()):
        for rooms in list(data.loc[~data['studio'] &
                                   data['kitchen_area'].isna() &
                                   (data['locality_name'] == locality) &
                                   (data['floors_total'] == floors),
                                   'rooms'].sort_values().unique()):

            min_value = data.loc[~data['studio'] &
                                 data['kitchen_area'].notna() &
                                 (data['locality_name'] == locality) &
                                 (data['floors_total'] == floors) &
                                 (data['rooms'] == rooms), 'kitchen_area'].min()

            data.loc[~data['studio'] &
                     data['kitchen_area'].isna() &
                     (data['locality_name'] == locality) &
                     (data['floors_total'] == floors) &
                     (data['rooms'] == rooms), 'kitchen_area'] = min_value

Количество записей, для которых не выполняется критерий, что площадь вспомогательных помещений (кроме кухни) должна составлять не менее 2 м².

In [297]:
len(data[~data['studio'] &
         (data['total_area'] < data['living_area'] + data['kitchen_area'] + 2)])
Out[297]:
15

Заменим в таких записях полученное значение жилой площади и значение площади кухни значением NaN.

In [298]:
data.loc[~data['studio'] &
         (data['total_area'] < data['living_area'] + data['kitchen_area'] + 2),
         'living_area'] = 0
data.loc[data['living_area'] == 0, 'kitchen_area'] = 0
data['living_area'].replace(0, np.nan, inplace=True)
data['kitchen_area'].replace(0, np.nan, inplace=True)

len(data[~data['studio'] &
         data['living_area'].isna() & data['kitchen_area'].isna()])
Out[298]:
118

Заполним средним арифметическим значением жилой площади, рассчитанным по известным значениям жилой площади объектов, расположенных во всех населённых пунктах, но в зданиях той же этажности и с тем же количеством жилых комнат.
То же самое выполняем и для значений площади кухни.

In [299]:
for floors in list(data.loc[~data['studio'] &
                            data['living_area'].isna(),
                            'floors_total'].sort_values().unique()):
    for rooms in list(data.loc[~data['studio'] &
                               data['living_area'].isna() &
                               (data['floors_total'] == floors),
                               'rooms'].sort_values().unique()):

        mean_value = data.loc[~data['studio'] &
                              data['living_area'].notna() &
                              (data['floors_total'] == floors) &
                              (data['rooms'] == rooms), 'living_area'].mean()

        data.loc[~data['studio'] &
                 data['living_area'].isna() &
                 (data['floors_total'] == floors) &
                 (data['rooms'] == rooms), 'living_area'] = mean_value
In [300]:
for floors in list(data.loc[~data['studio'] &
                            data['kitchen_area'].isna(),
                            'floors_total'].sort_values().unique()):
    for rooms in list(data.loc[~data['studio'] &
                               data['kitchen_area'].isna() &
                               (data['floors_total'] == floors),
                               'rooms'].sort_values().unique()):

        mean_value = data.loc[~data['studio'] &
                              data['kitchen_area'].notna() &
                              (data['floors_total'] == floors) &
                              (data['rooms'] == rooms), 'kitchen_area'].mean()

        data.loc[~data['studio'] &
                 data['kitchen_area'].isna() &
                 (data['floors_total'] == floors) &
                 (data['rooms'] == rooms), 'kitchen_area'] = mean_value

Количество записей, для которых не удалось рассчитать среднее значение жилой площади.

In [301]:
len(data[~data['studio'] &
         data['living_area'].isna() & data['kitchen_area'].isna()])
Out[301]:
3

Количество записей, для которых не выполняется критерий, что площадь вспомогательных помещений (кроме кухни) должна составлять не менее 2 м².

In [302]:
len(data[~data['studio'] &
         (data['total_area'] < data['living_area'] + data['kitchen_area'] + 2)])
Out[302]:
35

Заменим в таких записях полученное значение жилой площади и значение площади кухни значением NaN.

In [303]:
data.loc[~data['studio'] &
         (data['total_area'] < data['living_area'] + data['kitchen_area'] + 2),
         'living_area'] = 0
data.loc[data['living_area'] == 0, 'kitchen_area'] = 0
data['living_area'].replace(0, np.nan, inplace=True)
data['kitchen_area'].replace(0, np.nan, inplace=True)

len(data[~data['studio'] &
         data['living_area'].isna() &
         data['kitchen_area'].isna()])
Out[303]:
38

Заполним минимальным значением жилой площади, рассчитанным по известным значениям жилой площади объектов, расположенных во всех населённых пунктах, но в зданиях той же этажности и с тем же количеством жилых комнат.
То же самое выполняем и для значений площади кухни.

In [304]:
for floors in list(data.loc[~data['studio'] &
                            data['living_area'].isna(),
                            'floors_total'].sort_values().unique()):
    for rooms in list(data.loc[~data['studio'] &
                               data['living_area'].isna() &
                               (data['floors_total'] == floors),
                               'rooms'].sort_values().unique()):

        min_value = data.loc[~data['studio'] &
                             data['living_area'].notna() &
                             (data['floors_total'] == floors) &
                             (data['rooms'] == rooms), 'living_area'].min()

        data.loc[~data['studio'] &
                 data['living_area'].isna() &
                 (data['floors_total'] == floors) &
                 (data['rooms'] == rooms), 'living_area'] = min_value
In [305]:
for floors in list(data.loc[~data['studio'] &
                            data['kitchen_area'].isna(),
                            'floors_total'].sort_values().unique()):
    for rooms in list(data.loc[~data['studio'] &
                               data['kitchen_area'].isna() &
                               (data['floors_total'] == floors),
                               'rooms'].sort_values().unique()):

        min_value = data.loc[~data['studio'] &
                             data['kitchen_area'].notna() &
                             (data['floors_total'] == floors) &
                             (data['rooms'] == rooms), 'kitchen_area'].min()

        data.loc[~data['studio'] &
                 data['kitchen_area'].isna() &
                 (data['floors_total'] == floors) &
                 (data['rooms'] == rooms), 'kitchen_area'] = min_value

Количество записей, для которых не выполняется критерий, что площадь вспомогательных помещений (кроме кухни) должна составлять не менее 2 м².

In [306]:
len(data[~data['studio'] &
         (data['total_area'] < data['living_area'] + data['kitchen_area'] + 2)])
Out[306]:
3

Заменим в таких записях полученное значение жилой площади и значение площади кухни значением NaN.

In [307]:
data.loc[~data['studio'] &
         (data['total_area'] < data['living_area'] + data['kitchen_area'] + 2),
         'living_area'] = 0
data.loc[data['living_area'] == 0, 'kitchen_area'] = 0
data['living_area'].replace(0, np.nan, inplace=True)
data['kitchen_area'].replace(0, np.nan, inplace=True)

len(data[~data['studio'] &
         data['living_area'].isna() &
         data['kitchen_area'].isna()])
Out[307]:
6

Заполним средним арифметическим значением жилой площади, рассчитанным по известным значениям жилой площади объектов, расположенных во всех населённых пунктах, в зданиях любой этажности, но с тем же количеством жилых комнат.
То же самое выполняем и для значений площади кухни.

In [308]:
for rooms in list(data.loc[~data['studio'] &
                           data['living_area'].isna(),
                           'rooms'].sort_values().unique()):

    mean_value = data.loc[~data['studio'] &
                          data['living_area'].notna() &
                           (data['rooms'] == rooms), 'living_area'].mean()

    data.loc[~data['studio'] &
             data['living_area'].isna() &
              (data['rooms'] == rooms), 'living_area'] = mean_value
In [309]:
for rooms in list(data.loc[~data['studio'] &
                           data['kitchen_area'].isna(),
                           'rooms'].sort_values().unique()):

    mean_value = data.loc[~data['studio'] &
                          data['kitchen_area'].notna() &
                          (data['rooms'] == rooms), 'kitchen_area'].mean()

    data.loc[~data['studio'] &
             data['kitchen_area'].isna() &
             (data['rooms'] == rooms), 'kitchen_area'] = mean_value

Количество записей, для которых не удалось рассчитать среднее значение жилой площади.

In [310]:
len(data[~data['studio'] &
         data['living_area'].isna() &
         data['kitchen_area'].isna()])
Out[310]:
0

Количество записей, для которых не выполняется критерий, что площадь вспомогательных помещений (кроме кухни) должна составлять не менее 2 м².

In [311]:
len(data[~data['studio'] &
         (data['total_area'] < data['living_area'] + data['kitchen_area'] + 2)])
Out[311]:
3

Заменим в таких записях полученное значение жилой площади и значение площади кухни значением NaN.

In [312]:
data.loc[~data['studio'] &
         (data['total_area'] < data['living_area'] + data['kitchen_area'] + 2),
         'living_area'] = 0
data.loc[data['living_area'] == 0, 'kitchen_area'] = 0
data['living_area'].replace(0, np.nan, inplace=True)
data['kitchen_area'].replace(0, np.nan, inplace=True)

len(data[~data['studio'] &
         data['living_area'].isna() &
         data['kitchen_area'].isna()])
Out[312]:
3

Заполним минимальным значением жилой площади, рассчитанным по известным значениям жилой площади объектов, расположенных во всех населённых пунктах, в зданиях любой этажности, но с тем же количеством жилых комнат.
То же самое выполняем и для значений площади кухни.

In [313]:
for rooms in list(data.loc[~data['studio'] &
                           data['living_area'].isna(),
                           'rooms'].sort_values().unique()):

    min_value = data.loc[~data['studio'] &
                         data['living_area'].notna() &
                         (data['rooms'] == rooms), 'living_area'].min()

    data.loc[~data['studio'] &
             data['living_area'].isna() &
             (data['rooms'] == rooms), 'living_area'] = min_value
In [314]:
for rooms in list(data.loc[~data['studio'] &
                           data['kitchen_area'].isna(),
                           'rooms'].sort_values().unique()):

    min_value = data.loc[~data['studio'] &
                         data['kitchen_area'].notna() &
                         (data['rooms'] == rooms), 'kitchen_area'].min()

    data.loc[~data['studio'] &
             data['kitchen_area'].isna() &
             (data['rooms'] == rooms), 'kitchen_area'] = min_value

Количество записей, для которых не выполняется критерий, что площадь вспомогательных помещений (кроме кухни) должна составлять не менее 2 м².

In [315]:
len(data[~data['studio'] &
         (data['total_area'] < data['living_area'] + data['kitchen_area'] + 2)])
Out[315]:
0

Поскольку значения жилой площади и площади кухни определены с точностью до 0,01 м², округлим рассчитанные значения.

In [316]:
data['living_area'] = data['living_area'].round(2)
data['kitchen_area'] = data['kitchen_area'].round(2)
In [317]:
data['living_area'].value_counts().sort_index().head(12).index.tolist()
Out[317]:
[6.0, 6.5, 8.0, 8.3, 8.4, 8.5, 8.9, 9.0, 9.1, 9.8, 10.0, 10.08]
In [318]:
data['kitchen_area'].value_counts().sort_index().head(12).index.tolist()
Out[318]:
[2.0, 2.3, 2.32, 2.4, 2.55, 2.7, 2.82, 2.85, 2.89, 2.92, 3.0, 3.08]
In [319]:
show_na()
Всего пропусков %
ponds_nearest 5421 23.1
ponds_around_3000 5421 23.1
parks_nearest 5421 23.1
parks_around_3000 5421 23.1
city_centers_nearest 5421 23.1
airports_nearest 5421 23.1
days_exposition 3153 13.4
total_images 0 0.0
kitchen_area 0 0.0
locality_name 0 0.0
balcony 0 0.0
open_plan 0 0.0
last_price 0 0.0
studio 0 0.0
is_apartment 0 0.0
floor 0 0.0
living_area 0 0.0
floors_total 0 0.0
ceiling_height 0 0.0
rooms 0 0.0
first_day_exposition 0 0.0
total_area 0 0.0
locality_type 0 0.0

Картографические данные¶

Все пропущенные картографические данные находятся в одних и тех записях. Поскольку для этих записей невозможно восстановить значения картографических признаков, а таких записей значительное количество (23 %), необходимо их заполнить фиктивными значениями — метками. Значения расстояний до центра Санкт-Петербурга, центра аэропорта, ближайших парка и водоёма заполним значением 0 м, которое не противоречит физической природе величины, но в то же время не входит в интервал допустимых значений (не нарушает установленные критерии). Значения количества парков и водоёмов в радиусе 3 км заполним значением (−1).

In [320]:
data.loc[data['city_centers_nearest'].isna(), 'city_centers_nearest'] = 0
data.loc[data['airports_nearest'].isna(), 'airports_nearest'] = 0
data.loc[data['parks_nearest'].isna(), 'parks_nearest'] = 0
data.loc[data['ponds_nearest'].isna(), 'ponds_nearest'] = 0
data.loc[data['parks_around_3000'].isna(), 'parks_around_3000'] = -1
data.loc[data['ponds_around_3000'].isna(), 'ponds_around_3000'] = -1
In [321]:
show_na()
Всего пропусков %
days_exposition 3153 13.4
total_images 0 0.0
kitchen_area 0 0.0
ponds_nearest 0 0.0
ponds_around_3000 0 0.0
parks_nearest 0 0.0
parks_around_3000 0 0.0
city_centers_nearest 0 0.0
airports_nearest 0 0.0
locality_name 0 0.0
balcony 0 0.0
open_plan 0 0.0
last_price 0 0.0
studio 0 0.0
is_apartment 0 0.0
floor 0 0.0
living_area 0 0.0
floors_total 0 0.0
ceiling_height 0 0.0
rooms 0 0.0
first_day_exposition 0 0.0
total_area 0 0.0
locality_type 0 0.0

Обработка хронометрических данных¶

Пропущенные значения признака days_exposition есть преимущественно в записях, опубликованных за последнее время.

In [322]:
sns.heatmap(data.sort_values(by='first_day_exposition').isna(),
            cmap=sns.color_palette(['#000000', '#ffffff']))
plt.title('Тепловая карта\nраспределения пропущенных значений')
plt.xlabel('Название признака')
plt.ylabel('Номер записи')
plt.show()

Преобразуем формат object признака first_day_exposition к формату даты и времени.

In [323]:
data['first_day_exposition'] = pd.to_datetime(data['first_day_exposition'],
                                              format='%Y-%m-%dT%H:%M:%S')
data['first_day_exposition'].dtype
Out[323]:
dtype('<M8[ns]')

Будем считать, что к моменту выгрузки (к последней дате в наборе данных) все объявления, не имеющие значение в признаке days_exposition, всё ещё оставались опубликованными. Вычислим, какое количество дней прошло с момента публикации до момента получения набора данных и добавим к этому значению 1 день, поскольку на момент получения набора данных объявление ещё не было снято с публикации, а это уже как минимум один день публикации (поскольку время публикации (часы, минуты, секунды) приложением не фиксируется).

Значит, к моменту получения набора данных объявление не было снято в течение стольких дней, сколько прошло с момента публикации до момента получения набора данных.

Для того чтобы дополнительно выделить эти записи, добавим к значению количества дней публикации знак "минус".

In [324]:
data.loc[data['days_exposition'].isna(), 'days_exposition'] = \
(pd.to_timedelta(data['first_day_exposition'].max() -
                 data.loc[data['days_exposition'].isna(),
                          'first_day_exposition']).dt.days + 1) * (-1)
In [325]:
data['days_exposition'].sort_values().head(20).unique()
Out[325]:
array([-1619., -1608., -1607., -1606., -1605., -1604., -1589., -1582.,
       -1570.])
In [326]:
data['days_exposition'].sort_values().tail(20).unique()
Out[326]:
array([1396., 1406., 1413., 1417., 1430., 1434., 1441., 1452., 1458.,
       1477., 1484., 1485., 1489., 1497., 1512., 1513., 1553., 1572.,
       1580.])
In [327]:
show_na()
Всего пропусков %
total_images 0 0.0
kitchen_area 0 0.0
days_exposition 0 0.0
ponds_nearest 0 0.0
ponds_around_3000 0 0.0
parks_nearest 0 0.0
parks_around_3000 0 0.0
city_centers_nearest 0 0.0
airports_nearest 0 0.0
locality_name 0 0.0
balcony 0 0.0
open_plan 0 0.0
last_price 0 0.0
studio 0 0.0
is_apartment 0 0.0
floor 0 0.0
living_area 0 0.0
floors_total 0 0.0
ceiling_height 0 0.0
rooms 0 0.0
first_day_exposition 0 0.0
total_area 0 0.0
locality_type 0 0.0

Изменение типов данных¶

In [328]:
data.dtypes
Out[328]:
total_images                     int64
last_price                     float64
total_area                     float64
first_day_exposition    datetime64[ns]
rooms                            int64
ceiling_height                 float64
floors_total                   float64
living_area                    float64
floor                            int64
is_apartment                      bool
studio                            bool
open_plan                         bool
kitchen_area                   float64
balcony                        float64
locality_name                   object
airports_nearest               float64
city_centers_nearest           float64
parks_around_3000              float64
parks_nearest                  float64
ponds_around_3000              float64
ponds_nearest                  float64
days_exposition                float64
locality_type                   object
dtype: object

Значения признаков last_price, floors_total, balcony, parks_around_3000, ponds_around_3000, days_exposition являются целочисленными, а значения признаков city_centers_nearest, airports_nearest, parks_nearest, ponds_nearest определены с точностью до 1 м, поэтому их тип необходимо изменить на int64.

In [329]:
columns = ['last_price', 'floors_total', 'balcony', 'city_centers_nearest',
           'airports_nearest', 'parks_nearest', 'ponds_nearest',
           'parks_around_3000', 'ponds_around_3000', 'days_exposition']

data[columns] = data[columns].astype('int64')
In [330]:
data.dtypes
Out[330]:
total_images                     int64
last_price                       int64
total_area                     float64
first_day_exposition    datetime64[ns]
rooms                            int64
ceiling_height                 float64
floors_total                     int64
living_area                    float64
floor                            int64
is_apartment                      bool
studio                            bool
open_plan                         bool
kitchen_area                   float64
balcony                          int64
locality_name                   object
airports_nearest                 int64
city_centers_nearest             int64
parks_around_3000                int64
parks_nearest                    int64
ponds_around_3000                int64
ponds_nearest                    int64
days_exposition                  int64
locality_type                   object
dtype: object

Обработка дубликатов¶

Полные дубликаты в наборе данных отсутствуют.

In [331]:
data.duplicated().sum()
Out[331]:
0

Кандидатов в дубли в наборе данных — 21. Кандидаты в дубли выявлены по данным об объекте недвижимости (общей площади, количестве комнат, этаже), по данным о здании (этажность, местоположение) и по дате публикации. Все эти данные были изначально в наборе данных заполненными (практически полностью). Кроме того, день публикации является обязательным критерием сравнения, поскольку объявления о продаже одного и того же объекта недвижимости может публиковаться несколько раз, что может свидетельствовать о перепродаже этого объекта.

In [332]:
columns = ['first_day_exposition', 'total_area', 'rooms',
           'floor', 'locality_name', 'floors_total']

data[columns][data.duplicated(columns, keep=False)] \
              .sort_values(by=['first_day_exposition', 'total_area']).head(10)
Out[332]:
first_day_exposition total_area rooms floor locality_name floors_total
5783 2015-02-09 35.46 1 20 Санкт-Петербург 21
10852 2015-02-09 35.46 1 20 Санкт-Петербург 21
5155 2017-04-14 84.10 2 4 Санкт-Петербург 5
17989 2017-04-14 84.10 2 4 Санкт-Петербург 5
6827 2017-08-15 60.00 3 8 Санкт-Петербург 9
18534 2017-08-15 60.00 3 8 Санкт-Петербург 9
5241 2017-09-13 30.00 1 5 Санкт-Петербург 9
12650 2017-09-13 30.00 1 5 Санкт-Петербург 9
1666 2017-10-13 34.00 1 7 Санкт-Петербург 9
16291 2017-10-13 34.00 1 7 Санкт-Петербург 9
In [333]:
data[columns].duplicated().sum()
Out[333]:
21
In [334]:
len(data)
Out[334]:
23460

Удаляем кандидаты в дубликаты.

In [335]:
data.drop_duplicates(subset=columns, inplace=True)
data[columns].duplicated().sum()
Out[335]:
0
In [336]:
len(data)
Out[336]:
23439

Последние приготовления.

Отсортируем записи по значению дня публикации в хронологическом порядке и проиндексируем записи непрерывным рядом значений.

In [337]:
data = data.sort_values(by='first_day_exposition').reset_index(drop=True)
In [338]:
data.head()
Out[338]:
total_images last_price total_area first_day_exposition rooms ceiling_height floors_total living_area floor is_apartment studio open_plan kitchen_area balcony locality_name airports_nearest city_centers_nearest parks_around_3000 parks_nearest ponds_around_3000 ponds_nearest days_exposition locality_type
0 7 20100000 117.60 2014-11-27 3 3.0 8 62.50 7 False False False 21.50 0 Санкт-Петербург 39393 11096 1 537 0 0 -1619 город
1 1 12036000 100.00 2014-11-27 3 2.7 16 52.00 3 False False False 11.00 1 Санкт-Петербург 37407 8434 1 456 2 454 606 город
2 2 14500000 97.40 2014-11-27 2 3.0 8 36.30 2 False False False 31.70 0 Санкт-Петербург 39393 11096 1 537 0 0 1078 город
3 2 16137000 154.76 2014-11-27 4 2.7 20 67.81 20 False False False 32.55 0 Санкт-Петербург 18490 17492 0 0 2 113 573 город
4 8 8200000 52.50 2014-11-27 1 3.0 8 21.50 2 False False False 15.10 0 Санкт-Петербург 39393 11096 1 537 0 0 -1619 город
In [339]:
data.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 23439 entries, 0 to 23438
Data columns (total 23 columns):
 #   Column                Non-Null Count  Dtype         
---  ------                --------------  -----         
 0   total_images          23439 non-null  int64         
 1   last_price            23439 non-null  int64         
 2   total_area            23439 non-null  float64       
 3   first_day_exposition  23439 non-null  datetime64[ns]
 4   rooms                 23439 non-null  int64         
 5   ceiling_height        23439 non-null  float64       
 6   floors_total          23439 non-null  int64         
 7   living_area           23439 non-null  float64       
 8   floor                 23439 non-null  int64         
 9   is_apartment          23439 non-null  bool          
 10  studio                23439 non-null  bool          
 11  open_plan             23439 non-null  bool          
 12  kitchen_area          23439 non-null  float64       
 13  balcony               23439 non-null  int64         
 14  locality_name         23439 non-null  object        
 15  airports_nearest      23439 non-null  int64         
 16  city_centers_nearest  23439 non-null  int64         
 17  parks_around_3000     23439 non-null  int64         
 18  parks_nearest         23439 non-null  int64         
 19  ponds_around_3000     23439 non-null  int64         
 20  ponds_nearest         23439 non-null  int64         
 21  days_exposition       23439 non-null  int64         
 22  locality_type         23439 non-null  object        
dtypes: bool(3), datetime64[ns](1), float64(4), int64(13), object(2)
memory usage: 3.6+ MB

Обогащение данных¶

Создание производных признаков¶

Создание признака "Последний день публикации объявления".

In [340]:
data['last_day_exposition'] = (pd.to_datetime(data['first_day_exposition']) + \
                               pd.to_timedelta(abs(data['days_exposition']),
                                               unit='D')).dt.date
data['last_day_exposition'] = pd.to_datetime(data['last_day_exposition'])
data[['first_day_exposition', 'last_day_exposition']].head()
Out[340]:
first_day_exposition last_day_exposition
0 2014-11-27 2019-05-04
1 2014-11-27 2016-07-25
2 2014-11-27 2017-11-09
3 2014-11-27 2016-06-22
4 2014-11-27 2019-05-04
In [341]:
data['last_day_exposition'].dtypes
Out[341]:
dtype('<M8[ns]')

Перевод значений расстояний в километры.

In [342]:
data['city_centers_km'] = (data['city_centers_nearest'] / 1000).round(1)
data['airports_km'] = (data['airports_nearest'] / 1000).round(1)
data['parks_km'] = (data['parks_nearest'] / 1000).round(1)
data['ponds_km'] = (data['ponds_nearest'] / 1000).round(1)

Создание признака "Цена одного квадратного метра".

In [343]:
data['price_per_square_meter'] = (data['last_price'] / data['total_area']).round(0)
data['price_per_square_meter'] = data['price_per_square_meter'].astype('int')

Создание признаков "День недели", "Месяц", "Год" публикации объявления.

In [344]:
data['year'] = data['first_day_exposition'].dt.year
data['month'] = data['first_day_exposition'].dt.month
data['weekday'] = data['first_day_exposition'].dt.weekday
In [345]:
data.columns
Out[345]:
Index(['total_images', 'last_price', 'total_area', 'first_day_exposition',
       'rooms', 'ceiling_height', 'floors_total', 'living_area', 'floor',
       'is_apartment', 'studio', 'open_plan', 'kitchen_area', 'balcony',
       'locality_name', 'airports_nearest', 'city_centers_nearest',
       'parks_around_3000', 'parks_nearest', 'ponds_around_3000',
       'ponds_nearest', 'days_exposition', 'locality_type',
       'last_day_exposition', 'city_centers_km', 'airports_km', 'parks_km',
       'ponds_km', 'price_per_square_meter', 'year', 'month', 'weekday'],
      dtype='object')

Категоризация данных¶

Создание признака "Тип этажа квартиры".

In [346]:
def floor_type_categorize(row):
    if row['floor'] == 1:
        return 'первый'
    elif row['floor'] == row['floors_total']:
        return 'последний'
    else:
        return 'другой'
In [347]:
data['floor_type'] = data.apply(floor_type_categorize, axis = 1)
data['floor_type'].unique()
Out[347]:
array(['другой', 'последний', 'первый'], dtype=object)
In [348]:
data[['floor', 'floors_total', 'floor_type']].sample(7)
Out[348]:
floor floors_total floor_type
18041 3 6 другой
8935 2 9 другой
11190 8 10 другой
14855 1 4 первый
10687 3 6 другой
1746 3 5 другой
5322 13 16 другой

Создание признака "Является Санкт-Петербургом".

Обозначим некоторые населённые пункты, находящиеся в черте города Санкт-Петербурга, как Санкт-Петербург.

In [349]:
spb_locality = [
    'Зеленогорск', 'Колпино', 'Красное Село', 'Кронштадт', 'Ломоносов',
    'Павловск', 'Петергоф', 'Пушкин', 'Сестрорецк', 'Александровская',
    'Белоостров', 'Левашово', 'Лисий Нос', 'Металлострой', 'Молодёжное',
    'Парголово', 'Петро-Славянка', 'Понтонный', 'Репино', 'Сапёрный',
    'Стрельна', 'Усть-Ижора', 'Шушары', 'Санкт-Петербург'
]

for index in range(len(data)):
    if data.loc[index, 'locality_name'] in spb_locality:
        data.loc[index, 'is_spb'] = True
    else:
        data.loc[index, 'is_spb'] = False

Внесём данные о расстоянии до центра Санкт-Петербурга и аэропорта от населённых пунктов, расположенных в черте Санкт-Петербурга. Расстояния рассчитаем как среднее арифметическое значений, которые уже имеются в наборе данных для этих населённых пунктов.

In [350]:
for locality in list(data.loc[data['is_spb'] &
                              (data['city_centers_km'] == 0),
                              'locality_name'].unique()):
    data.loc[data['is_spb'] &
             (data['city_centers_km'] == 0) &
             (data['locality_name'] == locality),
             'city_centers_km'] = data.loc[data['locality_name'] == locality,
                                           'city_centers_km'].mean().round(1)
    data.loc[data['is_spb'] &
             (data['city_centers_km'] == 0) &
             (data['locality_name'] == locality),
             'airports_km'] = data.loc[data['locality_name'] == locality,
                                       'airports_km'].mean().round(1)
In [351]:
data['is_spb'].unique()
Out[351]:
array([True, False], dtype=object)
In [352]:
data.columns
Out[352]:
Index(['total_images', 'last_price', 'total_area', 'first_day_exposition',
       'rooms', 'ceiling_height', 'floors_total', 'living_area', 'floor',
       'is_apartment', 'studio', 'open_plan', 'kitchen_area', 'balcony',
       'locality_name', 'airports_nearest', 'city_centers_nearest',
       'parks_around_3000', 'parks_nearest', 'ponds_around_3000',
       'ponds_nearest', 'days_exposition', 'locality_type',
       'last_day_exposition', 'city_centers_km', 'airports_km', 'parks_km',
       'ponds_km', 'price_per_square_meter', 'year', 'month', 'weekday',
       'floor_type', 'is_spb'],
      dtype='object')

Промежуточный вывод

  • Выполнена предварительная обработка данных.
  • В результате предварительной обработки данных:
    • обработаны аномальные значения, противоречащие физической природе данных; где необходимо, установлены критерии для граничных значений (минимального и максимального),
    • устранены ошибки в значениях признаков,
    • удалены записи с несогласующимися значениями и значениями, для которых не определён населённый пункт,
    • извлечены вложенные сведения из признаков,
    • заполнены пропуски наиболее подходящим значением,
    • в записях, в которых не удалось подобрать подходящее значение, пропуски заполнены фиктивными значениями-метками, не противоречащими остальным данным,
    • типы данных приведены в соответствии с физической природой данных и шкалами их измерения,
    • обнаружены и удалены полные и частичные дубликаты,
    • сохранено 98,9 % записей исходного набора данных,
    • данные обогащены путём создания новых признаков и категоризации данных существующих признаков.

Исследовательский анализ данных¶

Описательный анализ данных¶

Предварительно зададим функцию, рассчитывающую описательные статистики.

In [353]:
def descriptive_statistics(values, label):
    '''
    Описательная статистика переменной, измеряемой в количественной шкале.

    Принимает значения признака и название признака.
    Возвращает DataFrame с набором статистик.

    '''

    df = pd.DataFrame([
        values.count(),
        len(values.unique()),
        values.min(),
        values.median() - 1.5 * (values.quantile(q=.75) -
                                 values.quantile(q=.25)),
        values.quantile(q=.25).round(2),
        (values.mode()).to_list(),
        values.median().round(2),
        values.mean().round(2),
        values.quantile(q=.75).round(2),
        values.median() + 1.5 * (values.quantile(q=.75) -
                                 values.quantile(q=.25)),
        values.max(),
        values.max() - values.min(),
        values.quantile(q=.75) - values.quantile(q=.25)
    ],
        index=['кол-во значений', 'кол-во уникальных', 'мин.',
               '-1.5IQR', '25 %', 'мода', 'медиана',
               'среднее ариф.', '75 %', '+1.5IQR', 'макс.',
               'размах', 'межквартильный размах'],
        columns=[label])

    return df

Хронометрические данные¶

Дата публикации объявления¶
In [354]:
stat = pd.DataFrame(
    pd.to_datetime(data['first_day_exposition']).dt.date.describe()
    ).rename(columns={'first_day_exposition': 'День публикации'},
             index={'count': 'кол-во значений',
                    'unique': 'кол-во уникальных',
                    'top': 'мода',
                    'freq': 'частота моды'}
).T
stat.loc['День публикации', 'мода'] = \
stat.loc['День публикации', 'мода'].strftime('%d.%m.%Y')

stat['мин'] = data['first_day_exposition'].min().strftime('%d.%m.%Y')
stat['медиана'] = data['first_day_exposition'].quantile(q=.5).strftime('%d.%m.%Y')
stat['макс'] = data['first_day_exposition'].max().strftime('%d.%m.%Y')
stat['размах'] = (data['first_day_exposition'].max() -
                  data['first_day_exposition'].min()).days + 1
stat['межквартильный размах'] = (data['first_day_exposition'].quantile(q=.75) -
                                 data['first_day_exposition'].quantile(q=.25)).days
stat.T
Out[354]:
День публикации
кол-во значений 23439
кол-во уникальных 1490
мода 01.02.2018
частота моды 359
мин 27.11.2014
медиана 11.12.2017
макс 03.05.2019
размах 1619
межквартильный размах 470
In [355]:
data['first_day_exposition'].value_counts().plot.box(
    title='Диаграма размаха распределения количества объявлений в день',
    xlabel='Количество объявлений в день',
    vert=False,
    figsize=(10, 2))
plt.tick_params(left=False, labelleft=False)
plt.show()
In [356]:
data['first_day_exposition'].value_counts().value_counts().sort_index().plot.bar(
    title='Диаграмма распределения количества дней ' +
          'по количеству публикуемых в день объявлений',
    xlabel='Количество объявлений в день',
    ylabel='Количество дней',
    figsize=(20, 5))
plt.show()

Медианное значение количества публикуемых в день объявлений

In [357]:
data['first_day_exposition'].value_counts().median()
Out[357]:
10.0
In [358]:
data.loc[data['is_spb'], 'first_day_exposition'].value_counts().plot.box(
    title='Диаграма размаха распределения количества' +
          '\nобъявлений в день о квартирах, расположенных в Санкт-Петербурге',
    xlabel='Количество объявлений в день',
    vert=False,
    figsize=(10, 2))
plt.tick_params(left=False, labelleft=False)
plt.show()
In [359]:
plt.title('Диаграмма распределения количества дней' +
          '\nпо количеству публикуемых в день объявлений')
data.loc[data['is_spb'], 'first_day_exposition'].value_counts().plot.hist(
    bins=[n + 1 for n in range(70)],
    figsize=(10, 3))
plt.xlabel('Количество объявлений в день')
plt.ylabel('Количество дней')
plt.show()
  • период наблюдения с 27.11.2014 г. по 03.05.2019 г. — 1619 дней — это почти 4,5 года
  • количество дней активности — 1490 — дни, в которые публиковались объявления в течение рассматриваемого периода — это 92 % дней или в среднем 336 дней в год
  • половина всех объявлений опубликована до 11.12.2017 — за первые 3 года наблюдаемого периода, а вторая половина — за 1,5 года, что свидетельствует об увеличении объёма публикуемых объявлений в единицу времени
  • самое большое количество объявлений в день — 359 — опубликовано 01.02.2018 г.
  • в среднем в день публикуется 10 объявлений (медианное значение) — на диаграмме распределения количества дней по количеству объявлений в день наблюдается излом
  • почти всегда количество публикуемых в день объявлений находится в диапазоне 1—50
  • дни с количеством публикуемых объявлений более 50 — редкие и единичные
  • форма распределения количества дней по количеству объявлений в день определяется главным образом формой такового распределения публикаций по дням с объявлениями о продаже квартир именно в Санкт-Петербурге
Год публикации объвления¶
In [360]:
data['year'].value_counts().describe().round(2)
Out[360]:
count       6.00
mean     3906.50
std      3521.10
min       134.00
25%      1577.75
50%      2803.50
75%      6795.25
max      8403.00
Name: count, dtype: float64
In [361]:
data['year'].value_counts().sort_index().plot.bar(
    rot=0,
    title='Диаграмма распределения\nколичества объявлений по годам публикации',
    xlabel='Год публикации',
    ylabel='Количество объявлений',
    figsize=(6, 3))
plt.show()

Таблица относительных частот.

In [362]:
pd.DataFrame((data['year'].value_counts() /
              data.shape[0] * 100).round(0).astype('int')) \
    .sort_index().reset_index() \
    .rename(columns={
        'year': 'Год',
        'count': 'Относительная частота, %'}
    ).set_index('Год').T
Out[362]:
Год 2014 2015 2016 2017 2018 2019
Относительная частота, % 1 5 12 35 36 12
In [363]:
pd.DataFrame(data.loc[(data['year'] > 2014) &
                      (data['year'] < 2019), 'year'].value_counts().sort_index()
            ).rename(columns={'count': 'Кол-во объявлений'}).plot.pie(
    figsize=(4, 4),
    title='Круговая диаграмма\nраспределения количества объявлений' +
          '\nпо годам за 2015—2018 гг.',
    subplots=True,
    ylabel='',
    legend=False,
    table=True)
plt.show()

Таблица относительных частот.

In [364]:
pd.DataFrame((data.loc[(data['year'] > 2014) &
                       (data['year'] < 2019), 'year'].value_counts() /
              data[(data['year'] > 2014) &
                   (data['year'] < 2019)].shape[0] * 100).round(0).astype('int')) \
    .sort_index().reset_index() \
    .rename(columns={
        'year': 'Год',
        'count': 'Относительная частота, %'}
    ).set_index('Год').T
Out[364]:
Год 2015 2016 2017 2018
Относительная частота, % 6 13 40 41
  • минимальное количество объявлений — 134 — опубликовано за 2014 год, поскольку до конца года оставалось чуть больше месяца
  • максимальное количество объявлений — 8403 — опубликовано за 2018 год
  • количество объявлений, опубликованных за первую треть 2019 года, сопоставимо с количеством объявлений, опубликованных за весь 2016 год
  • всего за рассматриваемый период времени в наборе данных содержатся объявления, опубликованные в 6 различных календарных годах
  • в рассматриваемом периоде содержатся полные 4 года — 2015—2018 гг., первая треть 2019 года и последний месяц 2014 года
  • за 4 полных года минимальное количество объявлений было опубликовано в 2015 году — 1183 объявления, что составляет 6 % всех объявлений за 4-х летний период
  • за 4 полных года максимальное количество объявлений было опубликовано в 2018 году — 8403 объявления, что составляет 41 % всех объявлений за 4-х летний период
  • в период с 2015 г. по 2017 г. включительно наблюдался значительный рост количества публикуемых в год объявлений:
    • на 1579 выросло количество публикуемых объявлений в 2016 году по сравнению с 2015 годом (увеличение почти в 2,5 раза)
    • на 5350 выросло количество публикуемых объявлений в 2017 году по сравнению с 2016 годом (увеличение почти в 3 раза)
    • на 291 выросло количество публикуемых объявлений в 2018 году по сравнению с 2017 годом (рост менее 4 %)
Месяц публикации объявления¶

Описательная статистика значений частот.

In [365]:
data['month'].value_counts().describe()
Out[365]:
count      12.000000
mean     1953.250000
std       438.902376
min      1259.000000
25%      1655.000000
50%      1854.500000
75%      2348.750000
max      2608.000000
Name: count, dtype: float64
In [366]:
plt.title('Диаграмма распределения\nколичества объявлений по месяцам')
data['month'].value_counts().sort_index().plot.bar(
    rot=0,
    figsize=(6, 3))
plt.xlabel('Месяц')
plt.ylabel('Количество объявлений')
plt.xticks(np.arange(12), ['янв.', 'фев.', 'мар.', 'апр.', 'май', 'июн.',
                           'июл.', 'авг.', 'сент.', 'окт.', 'нояб.', 'дек.'])
plt.show()

Таблица относительных частот.

In [367]:
pd.DataFrame((data['month'].value_counts() /
              data.shape[0] * 100).round(0).astype('int')) \
    .sort_index().reset_index() \
    .rename(columns={
        'month': 'Месяц',
        'count': 'Относительная частота, %'}
    ).set_index('Месяц').T
Out[367]:
Месяц 1 2 3 4 5 6 7 8 9 10 11 12
Относительная частота, % 6 11 11 10 5 7 7 7 8 9 10 7

Описательная статистика значений частот, рассчитанных для набора данных за период 2015—2018 гг.

In [368]:
data.loc[(data['year'] > 2014) &
         (data['year'] < 2019), 'month'].value_counts().describe().round(2)
Out[368]:
count      12.00
mean     1705.00
std       372.81
min      1069.00
25%      1480.25
50%      1709.00
75%      1986.50
max      2328.00
Name: count, dtype: float64
In [369]:
plt.title('Диаграмма распределения\nколичества объявлений по месяцам' +
          '\nза период 2015—2018 гг.')
data.loc[(data['year'] > 2014) &
         (data['year'] < 2019), 'month'].value_counts().sort_index().plot.bar(
    rot=0, figsize=(6, 3))
plt.xlabel('Месяц')
plt.ylabel('Количество объявлений')
plt.xticks(np.arange(12), ['янв.', 'фев.', 'мар.', 'апр.', 'май', 'июн.',
                           'июл.', 'авг.', 'сент.', 'окт.', 'нояб.', 'дек.'])
plt.show()
  • объявления публиковались в каждом из 12 месяцев
  • меньше всего объявлений публиковалось в мае (1259)
  • больше всего объявлений публиковалось в феврале (2608)
  • за полных 4 года распределение немного иное:
    • меньше всего объявлений публиковалось в январе (1069)
    • больше всего объявлений публиковалось в ноябре (2328)
    • на диаграмме наблюдается два максимума и два минимума
    • в феврале количество опубликованных объявлений выросло по сравнению с январём почти в два раза
    • с февраля по май наблюдается снижение количества публикуемых объявлений
    • с мая по июнь наблюдается рост количества публикуемых объявлений
    • с июня по август количество опубликованных объявлений остаётся на приблизительно одинаковом уровне
    • с августа по ноябрь наблюдается рост количества опубликованных объявлений
    • с ноября по январь происходит снижение количества публикуемых объявлений
In [370]:
plt.title('Диаграмма распределения\nколичества объявлений по каждому месяцу')
data['first_day_exposition'].groupby([data['first_day_exposition'].dt.year,
                                      data['first_day_exposition'].dt.month]
                                     ).count().plot.bar(figsize=(10, 3))
plt.xlabel('Год и месяц публикации')
plt.ylabel('Количество объявлений')
plt.show()
  • более подробное рассмотрение данных показывает неодинаковое изменение количества публикуемых объявлений при переходе от месяца к месяцу
    • в 2015 году рост наблюдается с апреля по декабрь
    • в 2016 году, наоборот, рост наблюдается с января по июнь, после чего наблюдается спад, который практически не изменяется до конца года
    • в 2017 году на протяжении всего года наблюдается рост количества публикуемых объявлений с максимумом в ноябре и снижением к концу года; также имеется резкий провал в марте
    • декабрь 2017 года и январь 2018 года можно также рассматривать как провал на диаграмме, поскольку рост, начавшийся в январе 2017 года достиг максимального значения в феврале 2018 года, после чего к маю 2018 произошёл спад количества публикуемых объявлений
    • с мая по июль 2018 года наблюдался рост количества публикуемых объявлений, а с июля по ноябрь 2018 года уровень сохранялся почти неизменным
    • к декабрю 2018 года наблюдается снижение числа публикуемых объявлений
    • с декабря 2018 года по апрель 2019 года наблюдается рост

Топ-10 дней с наибольшим количеством объявлений в день.

In [371]:
data['first_day_exposition'].value_counts().head(10).sort_index()
Out[371]:
first_day_exposition
2017-09-27    109
2017-09-28     74
2017-10-13    121
2017-11-10    239
2018-01-12     70
2018-02-01    359
2018-02-08     71
2018-03-06     70
2018-03-26     97
2018-07-10     92
Name: count, dtype: int64
In [372]:
plt.title('Диаграмма распределения\nколичества объявлений по каждому дню ' +
          'за период 01.01—28.02.2018 гг.')
data.loc[(data['year'] == 2018) & (data['month'] <= 2),
         'first_day_exposition'].groupby([data['first_day_exposition'].dt.month,
                                          data['first_day_exposition'].dt.day]
                                         ).count().plot.bar(figsize=(10, 3))
plt.xlabel('Месяц и число публикации')
plt.ylabel('Количество объявлений')
plt.show()
  • высокое значение количества публикуемых объявлений в феврале 2018 года и низкое значение в январе 2018 года, вероятно, обусловлено аномально большим значением количества (359) опубликованных объявлений 1 февраля 2018 года
  • причём последняя дата перед 1 февраля, когда были опубликованы объявления, была 23 января — очевидно, имеет место ошибка (баг) либо при публикации объявлений, либо при выгрузке данных, также могла иметь место техническая работа на сайте, в результате которой объявления, публикуемые в период 23 января — 1 февраля, были "реально" опубликованы в один день
In [373]:
plt.title('Диаграмма распределения\nколичества объявлений по каждому дню ' +
          'за период 01.09—30.11.2017 гг.')
data.loc[(data['year'] == 2017) & (data['month'] >= 9) & (data['month'] <= 11),
         'first_day_exposition'].groupby([data['first_day_exposition'].dt.month,
                                          data['first_day_exposition'].dt.day]
                                         ).count().plot.bar(figsize=(15, 3))
plt.xlabel('Месяц и число публикации')
plt.ylabel('Количество объявлений')
plt.show()
  • и хотя перед остальными днями с аномально высокими значениями количества публикуемых объявлений нет пропущенных дней, но пропущенные дни есть среди других чисел этого же месяца, но других лет. Возможно, отсутствие в наборе данных дат в месяце других лет, в котором есть аномальное значение в определённый год, также обусловлено ошибкой, например при записи или выгрузке данных
In [374]:
plt.title('Диаграмма распределения\nколичества объявлений по числам октября ' +
          'за 2015—2016 гг.')
data.loc[(data['year'] < 2017) & (data['month'] == 10),
         'first_day_exposition'].groupby([data['first_day_exposition'].dt.year,
                                          data['first_day_exposition'].dt.day]
                                         ).count().plot.bar(figsize=(10, 3))
plt.xlabel('Год и число публикации')
plt.ylabel('Количество объявлений')
plt.show()
  • да и в принципе, резко выбивающиеся значения могу свидетельствовать о том, что перед датой с выбивающимся значением частоты есть отсутствующие даты (например, 14.12.2015 г.)
In [375]:
data['day'] = pd.DatetimeIndex(data['first_day_exposition']).day
In [376]:
plt.title('Диаграмма распределения\nколичества объявлений, ' +
          'опубликованных 31 декабря или 1 января')
data.loc[((data['day'] == 31) & (data['month'] == 12)) |
         ((data['day'] == 1) & (data['month'] == 1)),
         'first_day_exposition'].groupby([data['first_day_exposition'].dt.year,
                                          data['first_day_exposition'].dt.day]
                                         ).count().plot.bar(rot=0, figsize=(10, 3))
plt.xlabel('Год и число публикации')
plt.ylabel('Количество объявлений')
plt.show()
  • занятен тот факт, что 31 декабря и 1 января обычно низкая активность (0—5 объявлений в день) нарушается необычно большим количеством опубликованных объявлений 1 января 2018 года — более 50
Дни недели¶
In [377]:
plt.title('Диаграмма распределения\nколичества объявлений по дням недели')
data['weekday'].value_counts().sort_index().plot.bar(rot=0, figsize=(5, 3))
plt.xlabel('День недели')
plt.ylabel('Количество объявлений')
plt.xticks(np.arange(7), ['пн', 'вт', 'ср', 'чт', 'пт', 'сб', 'вс'])
plt.show()

Таблица относительных частот.

In [378]:
pd.DataFrame((data['weekday'].value_counts() /
              data.shape[0] * 100).sort_index().round(0).astype('int')) \
    .sort_index().reset_index() \
    .rename(columns={
                'weekday': 'День недели',
                'count': 'Относительная частота, %'}
    ).set_index('День недели').rename(
        index={0: 'пн', 1: 'вт', 2: 'ср', 3: 'чт', 4: 'пт', 5: 'сб', 6: 'вс'}
    ).T
Out[378]:
День недели пн вт ср чт пт сб вс
Относительная частота, % 15 18 17 18 17 8 7
  • количество публикуемых объявлений в будние дни отличается от количества публикуемых объявлений в выходные
  • в субботу или воскресенье количество опубликованных объявлений в среднем в два раза меньше, чем в будний день (с понедельника по пятницу)
In [379]:
plt.title('Диаграмма распределения' +
          '\nколичества объявлений по месяцам и дням недели в течение 2018 года')
data.loc[data['year'] == 2018,
         'first_day_exposition'].groupby([data['first_day_exposition'].dt.month,
                                          data['first_day_exposition'].dt.weekday]
                                         ).count().plot.bar(figsize=(15, 3))
plt.xlabel('Месяц и день недели')
plt.ylabel('Количество объявлений')
plt.show()
  • в течение одного месяца распределение частот по дням недели меняется волнообразно, но и во все месяцы в течение года распределение количества публикуемых объявлений по дням недели также меняется волнообразно: увеличиваясь по будням и уменьшаясь к выходным
Количество дней публикации¶
In [380]:
descriptive_statistics(data.loc[data['days_exposition'] > 0, 'days_exposition'],
                       'Количество дней публикации')
Out[380]:
Количество дней публикации
кол-во значений 20289
кол-во уникальных 1141
мин. 1
-1.5IQR -184.5
25 % 45.0
мода [45]
медиана 96.0
среднее ариф. 181.42
75 % 232.0
+1.5IQR 376.5
макс. 1580
размах 1579
межквартильный размах 187.0
In [381]:
data.loc[data['days_exposition'] > 0, 'days_exposition'].plot.box(
    title='Диаграмма размаха' +
          '\nраспределения количества объявлений по количеству дней публикации' +
          '\n(для объявлений, снятых с публикации)',
    xlabel='Количество дней публикации',
    vert=False,
    figsize=(10, 2))
plt.tick_params(left=False, labelleft=False)
plt.show()
In [382]:
plt.title('Диаграмма распределения' +
          '\nколичества объявлений по количеству дней публикации' +
          '\n(для объявлений, снятых с публикации)')
data.loc[data['days_exposition'] > 0, 'days_exposition'].plot.hist(
    bins=[n + 1 for n in range(1580)],
    figsize=(10, 3))
plt.xlabel('Количество дней публикации')
plt.ylabel('Количество объявлений')
plt.ylim(0, 599)
plt.show()
In [383]:
plt.title('Диаграмма распределения' +
          '\nколичества объявлений по количеству дней публикации' +
          '\n(для объявлений, снятых с публикации)')
data.loc[data['days_exposition'] > 0, 'days_exposition'].plot.hist(
    bins=[n + 1 for n in range(100)],
    figsize=(10, 3))
plt.xlabel('Количество дней публикации')
plt.ylabel('Количество объявлений')
plt.show()

Топ-10 количества дней публикации.

In [384]:
data.loc[data['days_exposition'] > 0, 'days_exposition'].value_counts().head(10)
Out[384]:
days_exposition
45    873
60    532
7     224
30    208
90    204
4     174
3     156
5     150
14    147
9     140
Name: count, dtype: int64
  • всего известных значений в наборе данных — 20 289 — это 87 % всех данных
  • 3150 объявлений — это 13 % всех объявлений на момент 03.05.2019 остаются опубликованными
  • минимальное количество дней, когда объявление остаётся опубликованным, составляет 1 день
  • максимальное количество дней, когда объявление остаётся опубликованным, составляет 1580 дней — это почти 4,5 года, т. е. объявление оставалось опубликованным в течение всего периода, за который получен набор данных
  • среднее арифметическое всех значений составляет 181 день — это в два раза больше, чем медиана 96 дней, что обусловлено наличием справа длинного "хвоста" распределения значений
  • распределение сильно скошено влево
  • мода — 45 дней — совпадает с первым квартилем
  • в размах "усов" на диаграмме размаха попадают объявления, которые "висят" не более 376 дней — большинство объявлений снимается с публикации в течение года
  • на диаграмме распределения наблюдается ярко выраженный рост при значении 45 дней (мода)
  • в таблице частот можно заметить, что наибольшее количество объявлений остаются опубликованными в течение 7, 14, 30, 45, 90 дней; вероятно, имеет место "запрограммированное" количество дней публикации — возможно, эти объявления публиковали агентства недвижимости
In [385]:
days_exposed = data.loc[data['days_exposition'] > 0, 'days_exposition']
first_week = (days_exposed <= 7).sum()
second_week = ((days_exposed > 7) & (days_exposed <= 14)).sum()
first_month = ((days_exposed > 14) & (days_exposed <= 30)).sum()
month_and_half = ((days_exposed > 30) & (days_exposed <= 45)).sum()
second_month = ((days_exposed > 45) & (days_exposed <= 60)).sum()
third_month = ((days_exposed > 60) & (days_exposed <= 90)).sum()
half_year = ((days_exposed > 90) & (days_exposed <= 180)).sum()
first_year = ((days_exposed > 180) & (days_exposed <= 365)).sum()
more = (days_exposed > 365).sum()

days_exposed_category = pd.Series({'7 дн.': first_week,
                                   '14 дн.': second_week,
                                   '30 дн.': first_month,
                                   '45 дн.': month_and_half,
                                   '60 дн.': second_month,
                                   '90 дн.': third_month,
                                   '180 дн.': half_year,
                                   '365 дн.': first_year,
                                   'более года': more})

plt.title('Круговая диаграмма\nраспределения количества объявлений' +
          '\nпо количеству дней публикации\n(для объявлений, снятых с публикации)')
days_exposed_category.plot.pie(figsize=(4, 4))
plt.show()

Таблица относительных и куммулятивных частот.

In [386]:
days_exposed_category_percent = pd.DataFrame(
    days_exposed_category /
    len(days_exposed) * 100).round(0).astype('int').rename(
        columns={0: 'Относительная частота, %'}
    )

days_exposed_category_percent['Накопленная частота, %'] = \
days_exposed_category_percent.cumsum(axis=0)

days_exposed_category_percent.T
Out[386]:
7 дн. 14 дн. 30 дн. 45 дн. 60 дн. 90 дн. 180 дн. 365 дн. более года
Относительная частота, % 4 5 10 11 8 11 20 17 15
Накопленная частота, % 4 9 19 30 38 49 69 86 101
  • почти одну пятую всех объявлений снимают с публикации в течение 30 дней
  • более половины всех опубликованных объявлений снимают с публикации в течение 90 дней
  • 86 % всех объявлений снимают с публикации в течение года
  • каждые 15 дней в период два месяца с публикации снимаются 10 % опубликованных объявлений; далее скорость снятия объявлений снижается: 10 % за 30 дней, затем за 45 дней, затем за 60 дней
  • 15 % объявлений остаются опубликованными более года

Описательная статистика набора значений, относящихся к объявлениям, ещё не снятым с публикации.

In [387]:
abs(data.loc[data['days_exposition'] < 0,
             'days_exposition']).describe().round(0).astype('int')
Out[387]:
count    3150
mean      219
std       306
min         1
25%        32
50%        82
75%       277
max      1619
Name: days_exposition, dtype: int32
In [388]:
abs(data.loc[data['days_exposition'] < 0, 'days_exposition']).plot.box(
    title='Диаграмма размаха' +
          '\nраспределения количества объявлений по количеству дней публикации' +
          '\n(для объявлений, не снятых с публикации)',
    vert=False,
    xlabel='Количество дней публикации',
    figsize=(10, 2))
plt.tick_params(left=False, labelleft=False)
plt.show()
In [389]:
plt.title('Диаграмма распределения' +
          '\nколичества объявлений по количеству дней публикации' +
          '\n(для объявлений, не снятых с публикации)')
abs(data.loc[data['days_exposition'] < 0, 'days_exposition']).plot.hist(
    bins=[n + 1 for n in range(1619)],
    figsize=(10, 3))
plt.xlabel('Количество дней публикации')
plt.ylabel('Количество объявлений')
plt.ylim(0, 39)
plt.show()
In [390]:
days_exposed = data.loc[data['days_exposition'] < 0, 'days_exposition']
days_exposed = abs(days_exposed)
first_week = (days_exposed <= 7).sum()
second_week = ((days_exposed > 7) & (days_exposed <= 14)).sum()
first_month = ((days_exposed > 14) & (days_exposed <= 30)).sum()
month_and_half = ((days_exposed > 30) & (days_exposed <= 45)).sum()
second_month = ((days_exposed > 45) & (days_exposed <= 60)).sum()
third_month = ((days_exposed > 60) & (days_exposed <= 90)).sum()
half_year = ((days_exposed > 90) & (days_exposed <= 180)).sum()
first_year = ((days_exposed > 180) & (days_exposed <= 365)).sum()
more = (days_exposed > 365).sum()

days_exposed_category = pd.Series({'7 дн.': first_week,
                                   '14 дн.': second_week,
                                   '30 дн.': first_month,
                                   '45 дн.': month_and_half,
                                   '60 дн.': second_month,
                                   '90 дн.': third_month,
                                   '180 дн.': half_year,
                                   '365 дн.': first_year,
                                   'более года': more})

plt.title('Круговая диаграмма\nраспределения количества объявлений' +
          '\nпо количеству дней публикации' +
          '\n(для объявлений, не снятых с публикации)')
days_exposed_category.plot.pie(figsize=(3, 3))
plt.show()

Таблица относительных и куммулятивных частот.

In [391]:
days_exposed_category_percent = pd.DataFrame(
    days_exposed_category /
    len(days_exposed)*100).round(0).astype('int').rename(
        columns={0: 'Относительная частота, %'}
    )

days_exposed_category_percent['Накопленная частота, %'] = \
days_exposed_category_percent.cumsum(axis=0)

days_exposed_category_percent.T
Out[391]:
7 дн. 14 дн. 30 дн. 45 дн. 60 дн. 90 дн. 180 дн. 365 дн. более года
Относительная частота, % 5 6 13 9 8 10 12 16 20
Накопленная частота, % 5 11 24 33 41 51 63 79 99
  • из объявлений, оставшихся опубликованными к 03.05.2019 года, "висят" на сайте от 1 дня до 1619 дней (т. е. в течение всего наблюдаемого периода)
  • половина всех "висящих" объявлений находится на сайте около 3 месяцев
  • в каждые 15 дней (до 60 дней) укладывается по 10 % всех "висящих" объявлений
  • только одна пятая часть объявлений "висит" на сайте более одного года
  • большинство объявлений "висят" не более 650 дней (2 года)
Дата снятия с публикации¶
In [392]:
stat = pd.DataFrame(pd.to_datetime(
    data.loc[data['days_exposition'] > 0,
             'last_day_exposition']).dt.date.describe()
             ).rename(columns={'last_day_exposition': 'Последний день публикации'},
                      index={'count': 'кол-во значений',
                             'unique': 'кол-во уникальных',
                             'top': 'мода',
                             'freq': 'частота моды'}
                      ).T
stat.loc['Последний день публикации', 'мода'] = \
stat.loc['Последний день публикации', 'мода'].strftime('%d.%m.%Y')

stat['мин'] = data.loc[data['days_exposition'] > 0,
                       'last_day_exposition'].min().strftime('%d.%m.%Y')
stat['медиана'] = data.loc[data['days_exposition'] > 0,
                           'last_day_exposition'].quantile(q=.5).strftime('%d.%m.%Y')
stat['макс'] = data.loc[data['days_exposition'] > 0,
                        'last_day_exposition'].max().strftime('%d.%m.%Y')
stat['размах'] = (data.loc[data['days_exposition'] > 0, 'last_day_exposition'].max() -
                  data.loc[data['days_exposition'] > 0, 'last_day_exposition'].min()).days + 1
stat['межквартильный размах'] = (data.loc[data['days_exposition'] > 0,
                                          'last_day_exposition'].quantile(q=.75) -
                                 data.loc[data['days_exposition'] > 0,
                                          'last_day_exposition'].quantile(q=.25)).days
stat.T
Out[392]:
Последний день публикации
кол-во значений 20289
кол-во уникальных 1038
мода 23.01.2018
частота моды 487
мин 16.06.2016
медиана 04.04.2018
макс 02.05.2019
размах 1051
межквартильный размах 371
In [393]:
data.loc[data['days_exposition'] > 0,
         'last_day_exposition'].value_counts().plot.box(
    title='Диаграмма размаха\nраспределения количества объявлений,' +
          '\nснятых с публикации за один день',
    vert=False,
    xlabel='Количество объявлений',
    figsize=(10, 2))
plt.tick_params(left=False, labelleft=False)
plt.show()
In [394]:
data.loc[data['days_exposition'] > 0,
         'last_day_exposition'].value_counts().value_counts().sort_index().plot.bar(
    title='Диаграмма распределения количества дней по количеству объявлений, ' +
          'снятых с публикации за один день',
    xlabel='Количество снятых с публикации объявлений в день',
    ylabel='Количество дней',
    figsize=(15, 5))
plt.show()
  • 20 289 объявлений были сняты с публикации за 1038 различных дней
  • снимать с публикации объявления начали 16.06.2016 года — через 567 дней после начала рассматриваемого периода
  • последний день, когда было снято объявление, был 02.05.2019 — за 1 день до конца рассматриваемого периода
  • медианное значение попадает на 04.04.2018 года — таким образом, половина снятых с публикации объявлений была снята за два года в период 06.2016–04.2018, а вторая половина — за один год в период 04.2018–05.2019, что говорит об увеличении скорости не только публикации, но и снятия с публикации (и, как следствие, о популярности и востребованности ресурса)
  • только одно значение является аномальным и сильно выбивающимся из общего распределения — 487 объявлений было снято 23.01.2018 года
In [395]:
plt.title('Диаграмма распределения\nколичества объявлений' +
          '\nпо году и месяцу снятия объявления с публикации')
data.loc[data['days_exposition'] > 0,
         'last_day_exposition'].groupby([data['last_day_exposition'].dt.year,
                                         data['last_day_exposition'].dt.month]
                                        ).count().plot.bar(figsize=(10, 3))
plt.xlabel('Год и месяц снятия с публикации')
plt.ylabel('Количество объявлений')
plt.show()
  • на диаграмме распределения наблюдается рост с июня по июль 2016 года, а затем плавное снижение до конца года — в декабре 2016 года наблюдается минимум
  • с января 2017 года по март 2018 года наблюдается рост, причём в январе 2018 года наблюдается резкий максимум, вероятно, обусловленный аномальным значением — модой 487 объявлений
  • с марта по июнь 2018 года наблюдается спад количества снимаемых с публикации объявлений
  • с июня по ноябрь 2018 года наблюдается рост, а затем снижение к январю—февралю 2019 года
  • с февраля по апрель наблюдается рост количества снимаемых с публикации объявлений

Выеделение сведений о годе, месяце и дне недели последнего дня публикации.

In [396]:
data['last_year'] = pd.DatetimeIndex(data['last_day_exposition']).year
data['last_month'] = pd.DatetimeIndex(data['last_day_exposition']).month
data['last_weekday'] = pd.DatetimeIndex(data['last_day_exposition']).weekday

Топ-5 дней снятия объявления с публикации с максимальным количеством снятых объявлений в день.

In [397]:
data.loc[data['days_exposition'] > 0, 'last_day_exposition'].value_counts().head()
Out[397]:
last_day_exposition
2018-01-23    487
2018-03-26    106
2018-09-15    100
2018-12-18     94
2019-04-13     83
Name: count, dtype: int64
In [398]:
plt.title('Диаграмма распределения' +
          '\nколичества объявлений по числу снятия с публикации ' +
          'в период 01.01—28.02.2018 гг.')
data.loc[(data['days_exposition'] > 0) &
         (data['last_year'] == 2018) &
         (data['last_month'] <= 2),
         'last_day_exposition'].groupby([data['last_day_exposition'].dt.month,
                                         data['last_day_exposition'].dt.day]
                                        ).count().plot.bar(figsize=(10, 3))
plt.xlabel('Месяц и число снятия с публикации')
plt.ylabel('Количество объявлений')
plt.show()
  • среди дат снятия с публикации также, как и среди дат опубликования, есть отсутствующий период с 24 по 31 января 2018 года, причём аномальное значение приходится не на 1 февраля (конец этого периода), а на 23 января
  • вероятно, имеет место техническая ошибка или проведение технических работ в период с 24 по 31 января 2018 года
In [399]:
plt.title('Диаграмма распределения' +
          '\nколичества объявлений по году снятия с публикации')
data.loc[data['days_exposition'] > 0,
         'last_year'].value_counts().sort_index().plot.bar(rot=0, figsize=(7, 3))
plt.xlabel('Год')
plt.ylabel('Количество объявлений')
plt.show()
  • и хотя 2016 и 2019 годы неполные, всё же видно, что за 4 месяца 2019 года количество снятых с публикации объявлений выше, чем за 6,5 месяцев 2016 года
  • с 2017 по 2018 год наблюдается рост количества снимаемых с публикации объявлений в два раза
In [400]:
plt.title('Диаграмма распределения' +
          '\nколичества объявлений по месяцу снятия с публикации')
data.loc[(data['days_exposition'] > 0) &
         (data['last_year'] > 2016) &
         (data['last_year'] < 2019),
         'last_month'].value_counts().sort_index().plot.bar(rot=0, figsize=(7, 3))
plt.xlabel('Месяц')
plt.ylabel('Количество объявлений')
plt.xticks(np.arange(12), ['янв.', 'фев.', 'мар.', 'апр.', 'май', 'июн.',
                           'июл.', 'авг.', 'сент.', 'окт.', 'нояб.', 'дек.'])
plt.show()
  • в период с 2017 по 2018 год минимальное количество снимаемых с публикации объявлений приходилось на июнь, а максимальное — на ноябрь
In [401]:
plt.title('Диаграмма распределения\nколичества объявлений' +
          '\nпо дням недели снятия объявления с публикации')
data.loc[data['days_exposition'] > 0,
         'last_weekday'].value_counts().sort_index().plot.bar(rot=0, figsize=(7, 3))
plt.xlabel('День недели')
plt.ylabel('Количество объявлений')
plt.xticks(np.arange(7), ['пн', 'вт', 'ср', 'чт', 'пт', 'сб', 'вс'])
plt.show()
  • количество снимаемых с публикации объявлений в будние дни выше, чем в выходные, причём в воскресенье достигается наименьшее количество
  • картина распределения по дням недели повторяет такую же для дней публикации объявлений

Характеристики здания и его местоположения¶

Распределение квартир между городом и областью¶
In [402]:
data['is_spb'].astype('int').value_counts().rename(
    index={0: 'Область', 1: 'Город'}).plot.pie(
        title='Круговая диаграмма\nраспределения объявлений между' +
              '\nСанкт-Петербургом и Ленинградской областью',
        label='',
        figsize=(4, 4))
plt.show()
In [403]:
pd.DataFrame((data['is_spb'].astype('int').value_counts() /
              data.shape[0] * 100).round(0).astype('int')) \
    .sort_index().reset_index() \
    .rename(columns={
                'is_spb': 'Административная единица',
                'count': 'Относительная частота, %'}
    ).set_index('Административная единица') \
    .rename(index={0: 'Область', 1: 'Город'}).T
Out[403]:
Административная единица Область Город
Относительная частота, % 23 77
  • большинство объявлений — 77 % — содержат информацию о квартирах, расположенных в Санкт-Петербурге
  • 3 : 1 — соотношение количества объявлений о продаже квартир в Санкт-Петербурге и Ленинградской области
Тип населённого пункта¶
In [404]:
plt.title('Диаграмма распределения объявлений\nпо типу населённого пункта')
data['locality_type'].value_counts().plot.barh(figsize=(6, 3))
plt.xlabel('Количество объявлений')
plt.ylabel('Тип населённого пункта')
plt.show()

Таблица относительных частот.

In [405]:
pd.DataFrame((data['locality_type'].value_counts() /
              data.shape[0] * 100).round(1)) \
    .reset_index() \
    .rename(columns={
                'locality_type': 'Тип населённого пункта',
                'count': 'Относительная частота, %'}
    ).set_index('Тип населённого пункта')
Out[405]:
Относительная частота, %
Тип населённого пункта
город 84.7
посёлок 8.8
деревня 4.0
городской посёлок 2.3
село 0.1
посёлок при железнодорожной станции 0.1
In [406]:
urban = ((data['locality_type'] =='город') |
         (data['locality_type'] == 'городской посёлок')).sum()
not_urban = data.shape[0] - urban

plt.title('Круговая диаграмма\nраспределения объявлений' +
          '\nмежду городскими и сельскими\nнаселёнными пунктами')
pd.Series([urban, not_urban]).rename(
    index={0: 'Городские\nнаселённые пункты',
           1: 'Сельские\nнаселённые пункты'}
    ).plot.pie(figsize=(4, 4))
plt.show()
  • среди всех объявлений наибольшее количество относится к объектам недвижимости, расположенныы в городах, — это минимум на порядок больше, чем во всех остальных типах населённых пунктах
  • объекты недвижимости, расположенные в городских населённых пунктах (город и городской посёлок), составляют 87 %, а расположенные в сельских населённых пунктах — 13 %
  • почти 7 : 1 — отношение количества городских объектов недвижимости к сельским
  • среди сельских населённых пунктов наибольшее количество объектов недвижимости (около 9 % от всего набора данных) расположено в посёлках
Наименование населённых пунктов¶

Количество уникальных наименований населённых пунктов.

In [407]:
len(data['locality_name'].unique())
Out[407]:
298

Количество различных населённых пунктов Ленинградской области.

In [408]:
not_spb_unique_locality_number = pd.Series(
    {type: len(data.loc[(~data['is_spb']) & (data['locality_type'] == type),
                        'locality_name'].unique())
    for type in data['locality_type'].unique()})

not_spb_unique_locality_number.sum()
Out[408]:
286
In [409]:
plt.title('Круговая диаграмма\nраспределения объявлений' +
          '\nо продаже квартир в Ленинградской области' +
          '\nпо типу населённого пункта')
not_spb_unique_locality_number.plot.pie(figsize=(4, 4))
plt.show()

Таблица относительных частот.

In [410]:
pd.DataFrame(not_spb_unique_locality_number) \
    .reset_index() \
    .rename(columns={
                'index': 'Тип населённого пункта в Лен. обл.',
                0: 'Частота'}
    ).set_index('Тип населённого пункта в Лен. обл.')
Out[410]:
Частота
Тип населённого пункта в Лен. обл.
город 33
деревня 106
посёлок 97
городской посёлок 35
посёлок при железнодорожной станции 6
село 9

Количество населённых пунктов, расположенных в черте города Санкт-Петербурга.

In [411]:
in_spb_unique_locality_number = pd.Series(
    {type: len(data.loc[(data['is_spb']) & (data['locality_type'] == type),
                        'locality_name'].unique())
    for type in data['locality_type'].unique()})

in_spb_unique_locality_number.sum()
Out[411]:
24

Различные населённые пункты, имеющие одинаковое наименование.

In [412]:
for name in list(data['locality_name'].sort_values().unique()):
    type_list = list(data.loc[data['locality_name'] == name,
                              'locality_type'].unique())
    if len(type_list) > 1:
        print(name, '-', type_list)
Громово - ['посёлок', 'посёлок при железнодорожной станции']
Зимитицы - ['деревня', 'посёлок']
Калитино - ['деревня', 'посёлок']
Кудрово - ['деревня', 'город']
Любань - ['город', 'посёлок']
Мурино - ['посёлок', 'город']
Никольское - ['город', 'село']
Павлово - ['городской посёлок', 'село']
Рабитицы - ['деревня', 'посёлок']
Рябово - ['городской посёлок', 'посёлок']
Фёдоровское - ['деревня', 'городской посёлок']
Щеглово - ['посёлок', 'деревня']
  • количество уникальных наименований населённых пунктов — 298
  • часть населённых пунктов входит в состав города Санкт-Петербурга: в наборе данных содержится 23 таких наименования
  • в Ленинградской области находится 286 различных населённых пунктов
  • итого, в наборе данных содержится информация об объектах недвижимости, расположенных в 310 населённых пунктах
  • два населённых пункта в течение рассматриваемого периода изменили свой статус
    • 28.06.2018 года деревня Гарболово стала городом
    • 26.04.2019 года посёлок Мурино стал городом
  • таким образом, в наборе данных есть разные населённые пункты с одинаковым названием — таких названий 12
  • треть различных населённых пунктов в Ленинградской области приходится на деревни, а ещё треть — на посёлки
  • на города приходится только 10 % от всех населённых пунктов
  • таким образом, с учётом распределения по количеству объявлений между городскими и сельскими населёнными пунктами можно утверждать, что большое количество различных сельских населенных пунктов связано с малым количество выставляемой там на продажу недвижимости. В то же время, в небольшом количестве городских населённых пунктов выставляется на продажу значительное (преимущественное) количество объектов недвижимости
Расстояние до центра Санкт-Петербурга¶
In [413]:
plt.title('Круговая диаграмма\nраспределения объявлений' +
          '\nпо наличию значения расстояния\nдо центра Санкт-Петербурга')
(data['city_centers_km'] > 0).value_counts().rename(
    index={0: 'Нет', 1: 'Есть'}
    ).plot.pie(label='', figsize=(4, 4))
plt.show()

Таблица относительных частот.

In [414]:
pd.DataFrame((data['city_centers_km'] > 0).value_counts() /
             data.shape[0] * 100).round(0).astype('int') \
    .reset_index() \
    .rename(columns={
                'city_centers_km': 'Расстояние до центра Санкт-Петербурга',
                'count': 'Относительная частота, %'}
    ).set_index('Расстояние до центра Санкт-Петербурга').rename(
        index={0: 'не известно', 1: 'известно'}
    ).T
Out[414]:
Расстояние до центра Санкт-Петербурга известно не известно
Относительная частота, % 77 23
In [415]:
descriptive_statistics(data.loc[data['city_centers_km'] > 0, 'city_centers_km'],
                       'Расстояние до центра Санкт-Петербурга, км')
Out[415]:
Расстояние до центра Санкт-Петербурга, км
кол-во значений 18087
кол-во уникальных 456
мин. 0.2
-1.5IQR 2.6
25 % 9.3
мода [11.6]
медиана 13.1
среднее ариф. 14.21
75 % 16.3
+1.5IQR 23.6
макс. 66.0
размах 65.8
межквартильный размах 7.0

Количество значений, приходящихся на Санкт-Петербург.

In [416]:
data.loc[(data['is_spb']) & (data['city_centers_km'] > 0),
         'city_centers_km'].count()
Out[416]:
18080
In [417]:
plt.title('Диаграмма размаха\nраспределения объявлений по значению расстояния' +
          '\nот квартиры до центра Санкт-Петербурга')
data.loc[data['city_centers_km'] > 0, 'city_centers_km'].plot.box(
    vert=False,
    xlabel='Расстояние до центра Санкт-Петербурга, км',
    figsize=(10, 2))
plt.tick_params(left=False, labelleft=False)
plt.show()
In [418]:
plt.title('Диаграмма распределения объявлений' +
          '\nпо значению расстояния от квартиры\nдо центра Санкт-Петербурга')
data.loc[data['city_centers_km'] > 0, 'city_centers_km'].plot.hist(
    bins=[n + 1 for n in range(66)],
    figsize=(15, 3))
plt.xlabel('Расстояние до центра Санкт-Петербурга, км')
plt.ylabel('Количество объявлений')
plt.show()
In [419]:
plt.title('Диаграмма распределения объявлений' +
          '\nпо значению расстояния от квартиры\nдо центра Санкт-Петербурга')
data.loc[data['city_centers_km'] > 0, 'city_centers_km'].plot.hist(
    bins=[0.05 * (n + 1) for n in range(1400)],
    figsize=(15, 3))
plt.xlabel('Расстояние до центра Санкт-Петербурга, км')
plt.ylabel('Количество объявлений')
plt.show()

Топ-5 расстояний, наиболее распространённых в наборе данных.

In [420]:
pd.DataFrame(data.loc[data['city_centers_km'] > 0,
                      'city_centers_km'].value_counts()) \
    .reset_index() \
    .rename(columns={
                'city_centers_km': 'Расстояние до центра Санкт-Петербурга, км',
                'count': 'Относительная частота, %'}
    ).set_index('Расстояние до центра Санкт-Петербурга, км').head().T
Out[420]:
Расстояние до центра Санкт-Петербурга, км 11.6 14.8 11.9 12.0 14.9
Относительная частота, % 226 221 186 185 182
  • не для всех объявлений известно расстояние от центра Санкт-Петербурга до объекта недвижимости

  • только 77 % всех объявлений содержат значение расстояния до центра Санкт-Петербурга — это 18 020 объявлений

  • почти все значения относятся к объектам, расположенным в городе Санкт-Петербурге

  • минимальное значение 200 м, максимальное — 66 км

  • модой является значение 14,8 км, её частота — 221

  • медиана — 13, среднее арифметическое значение — 14; располагаются рядом и не сильно отличаются от моды

  • распределение значений мультимодальное, с длинным "хвостом" справа

  • наблюдаются пики с максимумами при значениях 5 км, 12 км, 15 км, небольшая группа с максимумом при 31 км и отдельно расположенная группа значений с максимумом при 52 км

  • половина всех значений лежит в пределах 9—16 км

  • большинство значений укладывается в диапазон 2,6—23,6 км

Расстояние до аэропорта¶
In [421]:
plt.title('Круговая диаграмма\nраспределения объявлений' +
          '\nпо наличию значения расстояния\nдо аэропорта')
(data['airports_km'] > 0).value_counts().rename(
    index={0: 'Нет', 1: 'Есть'}
    ).plot.pie(label='', figsize=(4, 4))
plt.show()

Таблица относительных частот.

In [422]:
pd.DataFrame((data['airports_km'] > 0).value_counts() /
             data.shape[0] * 100).round(0).astype('int') \
    .reset_index() \
    .rename(columns={
                'airports_km': 'Расстояние до аэропорта',
                'count': 'Относительная частота, %'}
    ).set_index('Расстояние до аэропорта').rename(
        index={0: 'не известно', 1: 'известно'}
    ).T
Out[422]:
Расстояние до аэропорта известно не известно
Относительная частота, % 77 23
In [423]:
descriptive_statistics(data.loc[data['airports_km'] > 0, 'airports_km'],
                       'Расстояние до аэропорта, км')
Out[423]:
Расстояние до аэропорта, км
кол-во значений 18020
кол-во уникальных 573
мин. 6.4
-1.5IQR -1.25
25 % 18.6
мода [37.4]
медиана 26.8
среднее ариф. 28.82
75 % 37.3
+1.5IQR 54.85
макс. 84.9
размах 78.5
межквартильный размах 18.7

Количество значений, приходящихся на Санкт-Петербург.

In [424]:
data.loc[(data['is_spb']) & (data['airports_km'] > 0), 'airports_km'].count()
Out[424]:
18013
In [425]:
plt.title('Диаграмма размаха\nраспределения объявлений по значению расстояния' +
          '\nот квартиры до аэропорта')
data.loc[data['airports_km'] > 0, 'airports_km'].plot.box(
    vert=False,
    xlabel='Расстояние до аэропорта, км',
    figsize=(10, 2))
plt.tick_params(left=False, labelleft=False)
plt.show()
In [426]:
plt.title('Диаграмма распределения объявлений' +
          '\nпо значению расстояния от квартиры\nдо аэропорта')
data.loc[data['airports_km'] > 0, 'airports_km'].plot.hist(
    bins=[n + 1 for n in range(66)],
    figsize=(15, 3))
plt.xlabel('Расстояние до аэропорта, км')
plt.ylabel('Количество объявлений')
plt.show()
In [427]:
plt.title('Диаграмма распределения объявлений' +
          '\nпо значению расстояния от квартиры\nдо аэропорта')
data.loc[data['airports_km'] > 0, 'airports_km'].plot.hist(
    bins=[0.05 * (n + 1) for n in range(1400)],
    figsize=(15, 3))
plt.xlabel('Расстояние до аэропорта, км')
plt.ylabel('Количество объявлений')
plt.show()

Топ-5 расстояний, наиболее распространённых в наборе данных.

In [428]:
pd.DataFrame(data.loc[data['airports_km'] > 0, 'airports_km'].value_counts()) \
    .reset_index() \
    .rename(columns={
                'airports_km': 'Расстояние до аэропорта, км',
                'count': 'Частота'}
    ).set_index('Расстояние до аэропорта, км').head().T
Out[428]:
Расстояние до аэропорта, км 37.4 23.6 21.9 18.7 14.8
Частота 130 128 99 97 97
  • не для всех объявлений известно расстояние от аэропорта до объекта недвижимости
  • только 77 % всех объявлений содержат значение расстояния до аэропорта — это 18 020 объявлений
  • почти все значения относятся к объектам, расположенным в городе Санкт-Петербурге
  • минимальное значение 6,4 км, максимальное — 84,9 км
  • модой является значение 37,4 км, её частота — 130; ближайшее по частоте значение — 23,6 км (встречается 128 раз)
  • медиана — 26, среднее арифметическое значение — 29 располагаются рядом и значительно отличаются от моды, однако лежат близко ко второму по распространённости значению
  • распределение значений мультимодальное, без явных пиков
  • половина всех значений лежат в пределах 18—37 км
  • большинство значений укладывается в диапазон 6,4—55 км
Количество парков¶
In [429]:
plt.title('Круговая диаграмма\nраспределения объявлений' +
          '\nпо количеству ближайших парков')
data['parks_around_3000'].value_counts().sort_index().rename(
    index={-1: 'Сведения\nотсутствуют', 0: 'Нет парков', 1: '1 парк',
           2: '2 парка', 3: '3 парка'}
    ).plot.pie(label='', figsize=(4, 4))
plt.show()

Таблица относительных частот.

In [430]:
pd.DataFrame((data['parks_around_3000'].value_counts() /
              data.shape[0] * 100).round(1).sort_index()) \
    .reset_index() \
    .rename(columns={
                'parks_around_3000': 'Количество парков',
                'count': 'Относительная частота, %'}
    ).set_index('Количество парков').rename(
        index={-1: 'Отсутствуют сведения', 0: 'Нет парков', 1: '1 парк',
               2: '2 парка', 3: '3 парка'}
    ).T
Out[430]:
Количество парков Отсутствуют сведения Нет парков 1 парк 2 парка 3 парка
Относительная частота, % 23.1 42.7 24.0 7.4 2.7
In [431]:
plt.title('Круговая диаграмма\nраспределения объявлений' +
          '\nпо количеству ближайших парков\nдля тех объектов недвижимости,' +
          '\nвокруг которых они есть')
data.loc[data['parks_around_3000'] > 0,
         'parks_around_3000'].value_counts().sort_index().rename(
            {1: '1 парк', 2: '2 парка', 3: '3 парка'}
        ).plot.pie(label='', figsize=(4, 4))
plt.show()

Таблица относительных частот.

In [432]:
pd.DataFrame((data.loc[data['parks_around_3000'] > 0,
                       'parks_around_3000'].value_counts() /
              data[data['parks_around_3000'] > 0].shape[0] * 100).round(1).sort_index()) \
    .reset_index() \
    .rename(columns={
                'parks_around_3000': 'Количество парков',
                'count': 'Относительная частота, %'}
    ).set_index('Количество парков').rename(
        index={1: '1 парк', 2: '2 парка', 3: '3 парка'}
    ).T
Out[432]:
Количество парков 1 парк 2 парка 3 парка
Относительная частота, % 70.4 21.6 8.0
  • не для всех объявлений известно количество парков в радиусе 3 км от объекта недвижимости
  • объявления, для которых нет картографических данных (а следовательно, и нет данных о количестве парков), составляют 23 % от общего числа объявлений
  • около 43 % объектов недвижимости не имеют в радиусе 3 км доступа к паркам
  • лишь для 34 % объявлений известно, что в радиусе 3 км от объекта недвижимости имеется по меньшей мере 1 парк
    • 70 % от этого количества имеют в радиусе 3 км 1 парк, 22 % — 2 парка и 8 % — 3 парка
  • отношение количества объектов недвижимости, имеющих доступ хотя бы к одному к парку, к количеству объектов недвижимости, не имеющих такового, составляет 5 : 4, то есть, почти поровну
Расстояние до ближайшего парка¶
In [433]:
descriptive_statistics(data.loc[data['parks_nearest'] > 0, 'parks_nearest'],
                       'Расстояние до ближайшего парка, м')
Out[433]:
Расстояние до ближайшего парка, м
кол-во значений 8007
кол-во уникальных 986
мин. 10
-1.5IQR -32.0
25 % 288.0
мода [441]
медиана 454.0
среднее ариф. 489.48
75 % 612.0
+1.5IQR 940.0
макс. 2984
размах 2974
межквартильный размах 324.0

Количество значений, приходящихся на Санкт-Петербург.

In [434]:
data.loc[(data['is_spb']) & (data['parks_nearest'] > 0), 'parks_nearest'].count()
Out[434]:
8007
In [435]:
plt.title('Диаграмма размаха\nраспределения объявлений' +
          '\nпо значению расстояния до ближайшего парка')
data.loc[data['parks_nearest'] > 0, 'parks_nearest'].plot.box(
    vert=False,
    xlabel='Расстояние до парка, м',
    figsize=(10, 2))
plt.tick_params(left=False, labelleft=False)
plt.show()
In [436]:
plt.title('Диаграмма распределения объявлений' +
          '\nпо значению расстояния от квартиры\nдо ближайшего парка')
data.loc[data['parks_nearest'] > 0, 'parks_nearest'].plot.hist(
    bins=[10 * (n + 1) for n in range(300)],
    figsize=(15, 3))
plt.xlabel('Расстояние до парка, м')
plt.ylabel('Количество объявлений')
plt.show()
In [437]:
plt.title('Диаграмма распределения объявлений' +
          '\nпо значению расстояния от квартиры\nдо ближайшего парка')
data.loc[data['parks_nearest'] > 0, 'parks_km'].plot.hist(
    bins=[0.01 * (n + 1) for n in range(300)],
    figsize=(15, 3))
plt.xlabel('Расстояние до парка, км')
plt.ylabel('Количество объявлений')
plt.show()

Топ-5 значений расстояний до ближайших парков (км).

In [438]:
pd.DataFrame(data.loc[data['parks_nearest'] > 0, 'parks_km'].value_counts()) \
    .reset_index() \
    .rename(columns={
                'parks_km': 'Расстояние до парка, км',
                'count': 'Частота'}
    ).set_index('Расстояние до парка, км').head().T
Out[438]:
Расстояние до парка, км 0.5 0.4 0.6 0.3 0.2
Частота 1356 1316 1121 998 931
  • 34 % всех объявлений имеют в радиусе 3 км по меньшей мере 1 парк — это 8007 объектов недвижимости
  • все из них расположены в черте города Санкт-Петербурга
  • распределение значений унимодальное, с большим количеством шума, имеет длинный "хвост" справа
  • медиана — 454 м, среднее арифметическое — 489 м и мода — 441 м; близко расположены
  • половина всех значений лежит в пределах 300—600 м
  • минимальное расстояние — 10 м — установлено нами как нижнее пороговое значение
  • максимальное значение — 2984 м
  • большинство значений не превышает 940 м
Количество водоёмов¶
In [439]:
plt.title('Круговая диаграмма\nраспределения объявлений' +
          '\nпо количеству ближайших водоёмов')
data['ponds_around_3000'].value_counts().sort_index().rename(
    index={-1: 'Сведения\nотсутствуют', 0: 'Нет водоёмов', 1: '1 водоём',
           2: '2 водоёма', 3: '3 водоёма'}
).plot.pie(label='', figsize=(4, 4))
plt.show()

Таблица относительных частот.

In [440]:
pd.DataFrame((data['ponds_around_3000'].value_counts() /
              data.shape[0] * 100).round(1).sort_index()) \
    .reset_index() \
    .rename(columns={
                'ponds_around_3000': 'Количество водоёмов',
                'count': 'Относительная частота, %'}
    ).set_index('Количество водоёмов').rename(
        index={-1: 'Сведения отсутствуют', 0: 'Нет водоёмов', 1: '1 водоём',
               2: '2 водоёма', 3: '3 водоёма'}
    ).T
Out[440]:
Количество водоёмов Сведения отсутствуют Нет водоёмов 1 водоём 2 водоёма 3 водоёма
Относительная частота, % 23.1 38.3 24.2 8.0 6.3
In [441]:
plt.title('Круговая диаграмма\nраспределения объявлений' +
          '\nпо количеству ближайших водоёмов\nдля тех объектов недвижимости,' +
          '\nвокруг которых они есть')
data.loc[data['ponds_around_3000'] > 0,
         'ponds_around_3000'].value_counts().sort_index().rename(
            {1: '1 водоём', 2: '2 водоёма', 3: '3 водоёма'}
        ).plot.pie(label='', figsize=(4, 4))
plt.show()

Таблица относительных частот.

In [442]:
pd.DataFrame((data.loc[data['ponds_around_3000'] > 0,
                       'ponds_around_3000'].value_counts() /
              data[data['ponds_around_3000'] > 0].shape[0] * 100).round(1).sort_index()) \
    .reset_index() \
    .rename(columns={
                'ponds_around_3000': 'Количество водоёмов',
                'count': 'Относительная частота, %'}
    ).set_index('Количество водоёмов').rename(
        index={1: '1 водоём', 2: '2 водоёма', 3: '3 водоёма'}
    ).T
Out[442]:
Количество водоёмов 1 водоём 2 водоёма 3 водоёма
Относительная частота, % 62.9 20.7 16.5
  • не для всех объявлений известно количество водоёмов в радиусе 3 км от объекта недвижимости
  • объявления, для которых нет картографических данных (а следовательно, и нет данных о количестве водоёмов), составляют 23 % от общего числа объявлений
  • около 38 % объектов недвижимости не имеют в радиусе 3 км доступа к водоёмам
  • лишь для 39 % объявлений известно, что в радиусе 3 км от объекта недвижимости имеется по меньшей мере 1 водоём
    • 63 % от этого количества имеют в радиусе 3 км 1 водоём, 21 % — 2 водоёма и 16 % — 3 водоёма
  • отношение количества объектов недвижимости, имеющих доступ хотя бы к одному водоёму, к количеству объектов недвижимости, не имеющих такового, составляет 1 : 1, то есть, поровну
Расстояние до ближайшего водоёма¶
In [443]:
descriptive_statistics(data.loc[data['ponds_nearest'] > 0, 'ponds_nearest'],
                       'Расстояние до ближайшего водоёма, м')
Out[443]:
Расстояние до ближайшего водоёма, м
кол-во значений 9033
кол-во уникальных 1096
мин. 13
-1.5IQR -152.0
25 % 294.0
мода [427]
медиана 502.0
среднее ариф. 518.02
75 % 730.0
+1.5IQR 1156.0
макс. 1344
размах 1331
межквартильный размах 436.0

Количество значений, приходящихся на Санкт-Петербург.

In [444]:
data.loc[(data['is_spb']) & (data['ponds_nearest'] > 0), 'ponds_nearest'].count()
Out[444]:
9031
In [445]:
plt.title('Диаграмма размаха\nраспределения объявлений' +
          '\nпо значению расстояния до ближайшего водоёма')
data.loc[data['ponds_nearest'] > 0, 'ponds_nearest'].plot.box(
    vert=False,
    xlabel='Расстояние до водоёма, м',
    figsize=(10, 2))
plt.tick_params(left=False, labelleft=False)
plt.show()
In [446]:
plt.title('Диаграмма распределения объявлений' +
          '\nпо значению расстояния от квартиры\nдо ближайшего водоёма')
data.loc[data['ponds_nearest'] > 0, 'ponds_nearest'].plot.hist(
    bins=[10 * (n + 1) for n in range(300)],
    figsize=(15, 3))
plt.xlabel('Расстояние до ближайшего водоёма, м')
plt.ylabel('Количество объявлений')
plt.show()
In [447]:
plt.title('Диаграмма распределения объявлений' +
          '\nпо значению расстояния от квартиры\nдо ближайшего водоёма')
data.loc[data['ponds_nearest'] > 0, 'ponds_km'].plot.hist(
    bins=[0.01 * (n + 1) for n in range(300)],
    figsize=(15, 3))
plt.xlabel('Расстояние до ближайшего водоёма, км')
plt.ylabel('Количество объявлений')
plt.show()

Топ-5 значений расстояний до ближайших водоёмов (км).

In [448]:
pd.DataFrame(data.loc[data['ponds_nearest'] > 0, 'ponds_km'].value_counts()) \
    .reset_index() \
    .rename(columns={
                'ponds_km': 'Расстояние до водоёма, км',
                'count': 'Частота'}
    ).set_index('Расстояние до водоёма, км').head().T
Out[448]:
Расстояние до водоёма, км 0.4 0.5 0.6 0.2 0.7
Частота 1198 1050 1033 922 897
  • 38 % всех объявлений имеют в радиусе 3 км по меньшей мере 1 водоём — это 9033 объектов недвижимости
  • все из них (за исключением двух) расположены в черте города Санкт-Петербурга
  • распределение значений унимодальное, с большим количеством шума
  • медиана — 502, среднее арифметическое — 518; близко расположены; немного от них отличается мода — 427
  • половина всех значений лежит в пределах 300—700 м
  • минимальное расстояние — 13 м
  • максимальное значение — 1344 м
  • большинство значений не превышает 1156 м
Этажность зданий¶
In [449]:
descriptive_statistics(data['floors_total'], 'Этажность зданий')
Out[449]:
Этажность зданий
кол-во значений 23439
кол-во уникальных 30
мин. 1
-1.5IQR -7.5
25 % 5.0
мода [5]
медиана 9.0
среднее ариф. 10.7
75 % 16.0
+1.5IQR 25.5
макс. 35
размах 34
межквартильный размах 11.0
In [450]:
plt.title('Диаграмма распределения объявлений' +
          '\nпо этажности здания, в котором расположен объект недвижимости')
data['floors_total'].value_counts().sort_index().plot.bar(rot=0, figsize=(10, 3))
plt.xlabel('Этажность здания')
plt.ylabel('Количество объявлений')
plt.show()

Топ-7 этажностей зданий.

In [451]:
pd.DataFrame(data['floors_total'].value_counts()) \
    .reset_index() \
    .rename(columns={
                'floors_total': 'Этажность здания',
                'count': 'Частота'}
    ).set_index('Этажность здания').head(7).T
Out[451]:
Этажность здания 5 9 16 12 4 10 25
Частота 5735 3736 1360 1353 1186 1168 1080
In [452]:
floors_5 = (data['floors_total'] <= 5).sum()
floors_9 = ((data['floors_total'] > 5) & (data['floors_total'] <= 9)).sum()
floors_16 = ((data['floors_total'] > 9) & (data['floors_total'] <= 16)).sum()
floors_35 = ((data['floors_total'] > 16) & (data['floors_total'] <= 35)).sum()

plt.title('Круговая диаграмма\nраспределения объявлений\nпо этажности здания,' +
          '\nв котором расположен объект недвижимости')
floors_category = pd.Series({'1—5 эт.': floors_5,
                             '6—9 эт.': floors_9,
                             '10—16 эт.': floors_16,
                             '16—35 эт.': floors_35})
floors_category.plot.pie(figsize=(4, 4))
plt.show()

Таблица относительных частот.

In [453]:
pd.DataFrame(floors_category/len(data)*100).round(0).astype('int') \
    .reset_index() \
    .rename(columns={
                'index': 'Этажность здания',
                0: 'Относительная частота, %'}
    ).set_index('Этажность здания').T
Out[453]:
Этажность здания 1—5 эт. 6—9 эт. 10—16 эт. 16—35 эт.
Относительная частота, % 34 24 22 20
  • для всех объявлений определены значения этажности здания
  • минимальное значение — 1 этаж — свидетельствует, что в наборе объявлений есть либо 1-этажные здания, в которых расположены квартиры (таунхаусы), либо случайно попавшие в набор данных объявления о продаже домов из частного сектора
  • максимальное значение — 35 этажей — высота самого высокого здания Санкт-Петербурга
  • медиана — 9 этажей
  • мода — 5 этажей, её частота — 5735 — это 24,5 % всех значений
  • на диаграмме распределения видно, что наибольшее значение приходится на дома в 5, 9, 12, 16, 25 этажей — среди которых много типовых зданий; кроме этого, распространены здания в 4 и 10 этажей

Характеристики объектов недвижимости¶

Тип этажа¶
In [454]:
plt.title('Круговая диаграмма\nраспределения объявлений' +
          '\nпо типу этажа, на котором\nрасположен объект недвижимости')
data['floor_type'].value_counts().plot.pie(label='', figsize=(4, 4))
plt.show()

Таблица относительных частот.

In [455]:
pd.DataFrame((data['floor_type'].value_counts() /
              data.shape[0] * 100).round(0).astype('int')) \
    .reset_index() \
    .rename(columns={
                'floor_type': 'Тип этажа',
                'count': 'Относительная частота, %'}
    ).set_index('Тип этажа').T
Out[455]:
Тип этажа другой последний первый
Относительная частота, % 74 14 12
  • количество объявлений об объектах недвижимости, расположенных на первом этаже, составляет 12 % от общего числа объявлений
  • приблизительно такая же часть объявлений — 14 % — относится к объектам недвижимости, расположенным на последних этажах
  • три четверти всех объявлений содержат информацию об объектах недвижимости, расположенных не на первом и не на последнем этажах
Номер этажа¶
In [456]:
plt.title('Диаграмма рапределения объявлений' +
          '\nпо номеру этажа, на котором расположен объект недвижимости')
data['floor'].value_counts().sort_index().plot.bar(rot=0, figsize=(10, 3))
plt.xlabel('Номер этажа')
plt.ylabel('Количество объявлений')
plt.show()
  • наибольшее число объектов недвижимости расположено с 1 по 5 этажи, включительно
  • самое распространённое расположение объекта недвижимости — на 2 этаже
  • почти в два раза реже встречаются объявления об объектах недвижимости, расположенных на этажах с 6 по 9, включительно
  • ещё в два раза реже встречаются объявления об объектах недвижимости, расположенных на этажах с 10 по 12
  • ещё более редкие — объекты недвижимости, расположенные на этажах с 12 по 17, включительно, причём частота для этих значений приблизительно одинаковая
  • редко встречаются объекты недвижимости, расположенные на этажах с 18 по 25
  • практически не встречаются объекты недвижимости, расположенные выше 25 этажа
Количество комнат¶
In [457]:
plt.title('Диаграмма рапределения объявлений\nпо количеству комнат в квартире')
data['rooms'].value_counts().sort_index().plot.bar(rot=0, figsize=(10, 3))
plt.xlabel('Количество комнат')
plt.ylabel('Количество объявлений')
plt.show()

Таблица частот.

In [458]:
pd.DataFrame(data['rooms'].value_counts().sort_index()) \
    .reset_index() \
    .rename(columns={
                'rooms': 'Количество комнат',
                'count': 'Частота'}
    ).set_index('Количество комнат').T
Out[458]:
Количество комнат 1 2 3 4 5 6 7 8 9 10 11 12 14 15 16 19
Частота 8114 7865 5766 1175 324 104 60 12 8 3 2 1 2 1 1 1
In [459]:
rooms_category = pd.Series({
    '1-комн. кв.': (data['rooms'] == 1).sum(),
    '2-комн. кв.': (data['rooms'] == 2).sum(),
    '3-комн. кв.': (data['rooms'] == 3).sum(),
    '4-комн. кв.': (data['rooms'] == 4).sum(),
    '(5+)-комн. кв.': (data['rooms'] >= 5).sum()
})

plt.title('Круговая диаграмма\nрапределения квартир по количеству комнат')
rooms_category.plot.pie(figsize=(4, 4))
plt.show()

Таблица относительных частот.

In [460]:
pd.DataFrame(rooms_category / len(data) * 100).round(1) \
    .reset_index() \
    .rename(columns={
                'index': 'Квартира',
                0: 'Относительная частота, %'}
    ).set_index('Квартира').T
Out[460]:
Квартира 1-комн. кв. 2-комн. кв. 3-комн. кв. 4-комн. кв. (5+)-комн. кв.
Относительная частота, % 34.6 33.6 24.6 5.0 2.2
  • большинство квартир — 1-, 2- или 3-комнатные: на них приходится почти 93 % всех объявлений
    • чуть больше трети всех объявлений приходится на 1-комнатные квартиры — мода значений
    • треть всех объявлений приходится на 2-комнатные квартиры
    • четверть всех объявлений приходится на 3-комнатные квартиры
  • лишь 5 % всех объявлений приходится на 4-комнатные квартиры
  • около 2 % объявлений приходится на квартиры с 5 и более жилыми комнатами
    • квартиры с количеством комнат 10 и более — единичные случаи
Общая площадь¶
In [461]:
descriptive_statistics(data['total_area'], 'Общая площадь, м$^2$')
Out[461]:
Общая площадь, м$^2$
кол-во значений 23439
кол-во уникальных 2159
мин. 13.0
-1.5IQR 7.0
25 % 40.0
мода [45.0]
медиана 52.0
среднее ариф. 60.44
75 % 70.0
+1.5IQR 97.0
макс. 900.0
размах 887.0
межквартильный размах 30.0
In [462]:
plt.title('Диаграмма размаха\nраспределения объявлений' +
          '\nпо значению общей площади объекта недвижимости')
data['total_area'].plot.box(
    vert=False,
    xlabel='Общая площадь, м$^2$',
    figsize=(10, 2))
plt.tick_params(left=False, labelleft=False)
plt.show()

Топ-10 значений общей площади объектов недвижимости.

In [463]:
pd.DataFrame(data['total_area'].value_counts()) \
    .reset_index() \
    .rename(columns={
                'total_area': 'Общая площадь, м$^2$',
                'count': 'Частота'}
    ).set_index('Общая площадь, м$^2$').head(10).T
Out[463]:
Общая площадь, м$^2$ 45.0 42.0 60.0 31.0 44.0 40.0 43.0 32.0 46.0 36.0
Частота 414 380 343 342 341 310 299 285 278 278
In [464]:
plt.title('Диаграмма распределения объявлений' +
          '\nпо значению общей площади объекта недвижимости')
data['total_area'].plot.hist(bins=[n + 1 for n in range(900)], figsize=(10, 3))
plt.xlabel('Общая площадь, м$^2$')
plt.ylabel('Количество объявлений')
plt.show()
In [465]:
plt.title('Диаграмма распределения объявлений' +
          '\nпо значениям общей площади объекта недвижимости,' +
          '\nпопадающим в размах "усов" на диаграмме размаха')
data.loc[data['total_area'] <= data['total_area'].median() +
         1.5 * (data['total_area'].quantile(q=.75) -
                data['total_area'].quantile(q=.25)),
         'total_area'].plot.hist(bins=[1 * (n + 1) for n in range(100)],
                                 figsize=(10, 3))
plt.xlabel('Общая площадь, м$^2$')
plt.ylabel('Количество объявлений')
plt.show()
In [466]:
plt.title('Диаграмма распределения объявлений' +
          '\nпо значениям общей площади объекта недвижимости,' +
          '\nпопадающим в размах "усов" на диаграмме размаха')
data.loc[data['total_area'] <= data['total_area'].median() +
         1.5 * (data['total_area'].quantile(q=.75) -
                data['total_area'].quantile(q=.25)),
         'total_area'].plot.hist(bins=[0.1 * (n + 1) for n in range(1000)],
                                 figsize=(15, 5),
                                 xticks=[10*m for m in range(11)])
plt.xlabel('Общая площадь, м$^2$')
plt.ylabel('Количество объявлений')
plt.show()
In [467]:
plt.title('Диаграмма распределения объявлений' +
          '\nпо значению общей площади объектов недвижимости,' +
          '\nсгруппированных по количеству комнат')
data.groupby('rooms')['total_area'].plot.hist(
    bins=[1 * (n + 1) for n in range(200)],
    alpha=0.5,
    figsize=(10, 3))
plt.xlabel('Общая площадь, м$^2$')
plt.ylabel('Количество объявлений')
plt.show()
  • значение общей площади известно для всех квартир
  • минимальное значение — 13 м$^2$
  • максимальное значение — 900 м$^2$, что является крайне редким значением
  • медиана — 52 м$^2$, среднее арифметическое — 60 м$^2$, мода — 45 м$^2$ расположены близко
  • половина всех объектов недвижимости имеют площадь от 40 до 70 м$^2$
  • общая площадь большинства объектов недвижимости не превышает 97 м$^2$
  • распределение значений мультимодальное, с длинным "хвостом" справа
  • значения общей площади преимущественно принимают целочисленные значения (с шагом 1 м$^2$)
  • разное количество максимумов на диаграмме распределения связано с распределением по площади квартир с разным количеством жилых комнат
Жилая площадь¶
In [468]:
descriptive_statistics(data['living_area'], 'Жилая площадь, м$^2$')
Out[468]:
Жилая площадь, м$^2$
кол-во значений 23439
кол-во уникальных 2001
мин. 6.0
-1.5IQR -5.7
25 % 18.5
мода [18.0]
медиана 30.0
среднее ариф. 34.25
75 % 42.3
+1.5IQR 65.7
макс. 409.7
размах 403.7
межквартильный размах 23.8
In [469]:
plt.title('Диаграмма размаха\nраспределения объявлений' +
          '\nпо значению жилой площади объекта недвижимости')
data['living_area'].plot.box(
    vert=False,
    xlabel='Жилая площадь, м$^2$',
    figsize=(10, 2))
plt.tick_params(left=False, labelleft=False)
plt.show()
In [470]:
plt.title('Диаграмма распределения объявлений' +
          '\nпо значению жилой площади объекта недвижимости')
data['living_area'].plot.hist(
    bins=[n + 1 for n in range(400)],
    figsize=(15, 3))
plt.xlabel('Жилая площадь, м$^2$')
plt.ylabel('Количество объявлений')
plt.show()
In [471]:
plt.title('Диаграмма распределения объявлений' +
          '\nпо значениям общей площади объекта недвижимости,' +
          '\nпопадающим в размах "усов" на диаграмме размаха')
data.loc[data['living_area'] <= data['living_area'].median() +
         1.5 * (data['living_area'].quantile(q=.75) -
                data['living_area'].quantile(q=.25)),
         'living_area'].plot.hist(bins=[n + 1 for n in range(70)],
                                  figsize=(10, 3))
plt.xlabel('Жилая площадь, м$^2$')
plt.ylabel('Количество объявлений')
plt.show()
In [472]:
plt.title('Диаграмма распределения объявлений' +
          '\nпо значениям общей площади объекта недвижимости,' +
          '\nпопадающим в размах "усов" на диаграмме размаха')
data.loc[data['living_area'] <= data['living_area'].median() +
         1.5 * (data['living_area'].quantile(q=.75) -
                data['living_area'].quantile(q=.25)),
         'living_area'].plot.hist(bins=[0.1 * (n + 1) for n in range(700)],
                                  figsize=(10, 3))
plt.xlabel('Жилая площадь, м$^2$')
plt.ylabel('Количество объявлений')
plt.show()
In [473]:
plt.title('Диаграмма распределения объявлений' +
          '\nпо значению жилой площади объектов недвижимости,' +
          '\nсгруппированных по количеству комнат')
data.groupby('rooms')['living_area'].plot.hist(bins=[(n + 1) for n in range(100)],
                                               alpha=0.5,
                                               figsize=(10, 3))
plt.xlabel('Жилая площадь, м$^2$')
plt.ylabel('Количество объявлений')
plt.show()

Описательная статистика значений площади, приходящихся в среднем на одну жилую комнату.

In [474]:
descriptive_statistics(data['living_area'] / data['rooms'],
                       'Площадь жилой комнаты, м$^2$')
Out[474]:
Площадь жилой комнаты, м$^2$
кол-во значений 23439
кол-во уникальных 2036
мин. 4.0
-1.5IQR 10.75
25 % 14.5
мода [18.0]
медиана 16.0
среднее ариф. 16.58
75 % 18.0
+1.5IQR 21.25
макс. 62.5
размах 58.5
межквартильный размах 3.5
In [475]:
plt.title('Диаграмма распределения объявлений\nпо среднему значению площади,' +
          '\nприходящейся на одну жилую комнату')
(data['living_area']/data['rooms']).plot.hist(bins=[n + 1 for n in range(63)])
plt.xlabel('Площадь жилой комнаты, м$^2$')
plt.ylabel('Количество объявлений')
plt.show()
  • для всех объявлений имеется значение жилой площади
  • минимальное значение — 6 м$^2$
  • максимальное — 410 м$^2$
  • медиана — 30 м$^2$, среднее арифметическое — 34 м$^2$ расположены близко, мода — 18 м$^2$ значительно отличается от них
  • половина всех объектов имеют жилую площадь от 18 до 42 м$^2$
  • жилая площадь большинства объектов недвижимости не превышает 66 м$^2$
  • распределение значений жилой площади мультимодальное, с длинным "хвостом" справа
  • значения жилой площади преимущественно принимают целочисленные значения (с шагом 1 м$^2$)
  • разное количество максимумов на диаграмме распределения связано с распределением по площади квартир с разным количеством жилых комнат
  • средняя площадь, приходящаяся на жилую комнату, распределена унимодально; распределение похоже на нормальное
Площадь кухни¶
In [476]:
descriptive_statistics(data['kitchen_area'], 'Площадь кухни, м$^2$')
Out[476]:
Площадь кухни, м$^2$
кол-во значений 23439
кол-во уникальных 1211
мин. 2.0
-1.5IQR 1.66
25 % 7.0
мода [6.0]
медиана 9.01
среднее ариф. 10.39
75 % 11.9
+1.5IQR 16.36
макс. 112.0
размах 110.0
межквартильный размах 4.9
In [477]:
plt.title('Диаграмма размаха\nраспределения объявлений' +
          '\nпо значению площади кухни объекта недвижимости')
data['kitchen_area'].plot.box(
    vert=False,
    xlabel='Площадь кухни, м$^2$',
    figsize=(10, 2))
plt.tick_params(left=False, labelleft=False)
plt.show()
In [478]:
plt.title('Диаграмма распределения объявлений' +
          '\nпо значению площади кухни объекта недвижимости')
data['kitchen_area'].plot.hist(bins=[1 * (n + 1) for n in range(125)],
                               figsize=(15, 3))
plt.xlabel('Площадь кухни, м$^2$')
plt.ylabel('Количество объявлений')
plt.show()
In [479]:
plt.title('Диаграмма распределения объявлений' +
          '\nпо значениям площади кухни объекта недвижимости,' +
          '\nпопадающим в размах "усов" на диаграмме размаха')
data.loc[data['kitchen_area'] <= data['kitchen_area'].median() +
         1.5 * (data['kitchen_area'].quantile(q=.75) -
                data['kitchen_area'].quantile(q=.25)),
         'kitchen_area'].plot.hist(bins=[0.05 * (n + 1) for n in range(400)],
                                   figsize=(10, 3),
                                   xticks=[2*m for m in range(11)])
plt.xlabel('Площадь кухни, м$^2$')
plt.ylabel('Количество объявлений')
plt.show()

Топ-10 значений площади кухни.

In [480]:
pd.DataFrame(data['kitchen_area'].value_counts()) \
    .reset_index() \
    .rename(columns={
                'kitchen_area': 'Площадь кухни, м$^2$',
                'count': 'Частота'}
    ).set_index('Площадь кухни, м$^2$').head(10).T
Out[480]:
Площадь кухни, м$^2$ 6.0 10.0 8.0 9.0 7.0 11.0 12.0 8.5 5.0 5.5
Частота 1298 1248 1115 1092 1070 791 653 417 414 407
In [481]:
plt.title('Диаграмма распределения объявлений' +
          '\nпо значению площади кухни объектов недвижимости,' +
          '\nсгруппированных по количеству комнат')
data.groupby('rooms')['kitchen_area'].plot.hist(bins=[n + 1 for n in range(30)],
                                                alpha=0.5)
plt.xlabel('Площадь кухни, м$^2$')
plt.ylabel('Количество объявлений')
plt.show()
  • для всех объявлений имеется значение площади кухни
  • минимальное значение — 2 м$^2$
  • максимальное — 112 м$^2$
  • медиана — 9 м$^2$, среднее арифметическое — 10 м$^2$ расположены близко, мода — 6 м$^2$ незначительно отличается от них
  • половина всех объектов имеют площадь кухни от 7 до 11 м$^2$
  • площадь кухни большинства объектов недвижимости не превышает 17 м$^2$
  • распределение значений площади кухни унимодальное, с длинным "хвостом" справа
  • значения площади кухни преимущественно принимают целочисленные значения (с шагом 1 м$^2$)
  • шумы в области максимума на диаграмме распределения связаны с распределением по площади кухни квартир с разным количеством жилых комнат
Количество балконов¶
In [482]:
plt.title('Диаграмма распределения объявлений' +
          '\nпо количеству балконов у объектов недвижимости')
data['balcony'].value_counts().sort_index().plot.bar(rot=0, figsize=(6, 3))
plt.xlabel('Количество балконов')
plt.ylabel('Количество объявлений')
plt.show()
In [483]:
pd.DataFrame((data['balcony'].value_counts() / data.shape[0] * 100).round(1)) \
    .reset_index() \
    .rename(columns={
                'balcony': 'Количество балконов',
                'count': 'Относительная частота, %'}
    ).set_index('Количество балконов').T
Out[483]:
Количество балконов 0 1 2 5 4 3
Относительная частота, % 64.5 17.7 15.4 1.3 0.8 0.3
  • большинство квартир не имеют балконов — 64,5 %, только 35,5 % объявлений имеют балконы
  • те квартиры, которые имеют балконы, преимущественно имеют 1 или 2 балкона
  • количество квартир, имеющих 1 или 2 балкона, приблизительно одинаковое
  • незначительное количество квартир имеют от 3 до 5 балконов — это менее 2,5 %
Высота потолков¶
In [484]:
descriptive_statistics(data['ceiling_height'], 'Высота потолков, м')
Out[484]:
Высота потолков, м
кол-во значений 23439
кол-во уникальных 167
мин. 2.0
-1.5IQR 2.26
25 % 2.5
мода [2.5]
медиана 2.65
среднее ариф. 2.7
75 % 2.76
+1.5IQR 3.04
макс. 6.0
размах 4.0
межквартильный размах 0.26
In [485]:
plt.title('Диаграмма размаха\nраспределения объявлений' +
          '\nпо значению высоты потолка объекта недвижимости')
data['ceiling_height'].plot.box(
    vert=False,
    xlabel='Высота потолка, м',
    figsize=(10, 2))
plt.tick_params(left=False, labelleft=False)
plt.show()
In [486]:
plt.title('Диаграмма распределения объявлений' +
          '\nпо значению высоты потолка у объектов недвижимости')
data['ceiling_height'].plot.hist(bins=[0.01 * (n + 1) + 2 for n in range(400)],
                                 figsize=(15, 3))
plt.xlabel('Высота потолков, м')
plt.ylabel('Количество объявлений')
plt.show()

Топ-7 значений высоты потолка.

In [487]:
pd.DataFrame((data['ceiling_height'].value_counts() /
              data.shape[0] * 100)).round(0).astype('int') \
    .reset_index() \
    .rename(columns={
                'ceiling_height': 'Высота потолка, м',
                'count': 'Относительная частота, %'}
    ).set_index('Высота потолка, м').head(7).T
Out[487]:
Высота потолка, м 2.50 2.70 2.60 3.00 2.75 2.80 2.55
Относительная частота, % 31 13 10 9 8 7 5
  • для всех квартир определены значения высоты потолков
  • минимальное значение — 2 м
  • максимальное значение — 6 м
  • медиана — 2,65 м, среднее арифметическое — 2,7 м и мода — 2,5 м расположены близко
  • значение 2,5 м встречается почти в трети объявлений, ближайшее значение 2,7 м встречается в два раза реже
  • половина всех значений расположено в очень узком интервале — между 2,5 м и 2,76 м
  • большинство значений расположено от 2,2 м до 3 м
  • распределение значений практически дискретное: около 80 % всех значений признака распределены между 8 значениями высоты потолка
Студия¶
In [488]:
plt.title('Круговая диаграмма распределения объявлений' +
          '\nпо факту того, является ли квартира студией')
data['studio'].astype('int').value_counts().rename(
    index={0: 'Не студия', 1: 'Студия'}
).plot.pie(label='', figsize=(4, 4))
plt.show()
In [489]:
pd.DataFrame((data['studio'].astype('int').value_counts() /
              data.shape[0] * 100)).round(1) \
    .reset_index() \
    .rename(columns={
                'studio': 'Является ли квартира студией',
                'count': 'Относительная частота, %'}
    ).set_index('Является ли квартира студией').rename(
        index={0: 'Не студия', 1: 'Студия'}
    ).T
Out[489]:
Является ли квартира студией Не студия Студия
Относительная частота, % 99.1 0.9
  • практически все объявления содержат информацию об объектах недвижимости, не являющихся квартирами-студиями
  • только 1 % всех объявлений приходится на квартиры-студии
Апартаменты¶
In [490]:
plt.title('Круговая диаграмма распределения объявлений' +
          '\nпо факту того, является ли квартира апартаментами')
data['is_apartment'].astype('int').value_counts().rename(
    index={0: 'Не апартаменты', 1: 'Апартаменты'}
).plot.pie(label='', figsize=(4, 4))
plt.show()
In [491]:
pd.DataFrame((data['is_apartment'].astype('int').value_counts() /
              data.shape[0] * 100)).round(1) \
    .reset_index() \
    .rename(columns={
                'is_apartment': 'Является ли квартира апартаментами',
                'count': 'Относительная частота, %'}
    ).set_index('Является ли квартира апартаментами').rename(
        index={0: 'Не апартаменты', 1: 'Апартаменты'}
    ).T
Out[491]:
Является ли квартира апартаментами Не апартаменты Апартаменты
Относительная частота, % 99.8 0.2
  • практически все объявления содержат информацию об объектах недвижимости, не являющихся апартаментами
  • только 0,2 % всех объявлений приходится на апартаменты

Финансовые характеристики¶

Цена на момент снятия с публикации¶
In [492]:
descriptive_statistics(data['last_price'], 'Цена объекта, руб.')
Out[492]:
Цена объекта, руб.
кол-во значений 23439
кол-во уникальных 2955
мин. 12190
-1.5IQR -390000.0
25 % 3440000.0
мода [4500000]
медиана 4650000.0
среднее ариф. 6551914.3
75 % 6800000.0
+1.5IQR 9690000.0
макс. 763000000
размах 762987810
межквартильный размах 3360000.0
In [493]:
plt.title('Диаграмма размаха' +
          '\nраспределения объявлений по цене объекта недвижимости')
data['last_price'].plot.box(
    vert=False,
    xlabel='Цена объекта, руб.',
    figsize=(10, 2))
plt.tick_params(left=False, labelleft=False)
plt.show()
In [494]:
plt.title('Диаграмма распределения объявлений\nпо цене объекта недвижимости')
data['last_price'].plot.hist(
    bins=[100000 * (n + 1) for n in range(300)],
    figsize=(10, 3))
plt.xlabel('Цена объекта, руб.')
plt.ylabel('Количество объявлений')
plt.show()
In [495]:
plt.title('Диаграмма распределения объявлений\nпо цене объекта недвижимости')
data['last_price'].plot.hist(
    bins=[10000 * (n + 1) for n in range(3000)],
    figsize=(10, 3))
plt.xlabel('Цена объекта, руб.')
plt.ylabel('Количество объявлений')
plt.show()

Топ-10 значений цены объекта по распространённости.

In [496]:
pd.DataFrame(data['last_price'].value_counts()) \
    .reset_index() \
    .rename(columns={
                'last_price': 'Цена квартиры, руб.',
                'count': 'Частота'}
    ).set_index('Цена квартиры, руб.').head(10).T
Out[496]:
Цена квартиры, руб. 4500000 3500000 4200000 4300000 4000000 3600000 3300000 3800000 3200000 4100000
Частота 339 287 259 258 257 256 240 238 237 231
  • для всех объявлений известна цена на момент снятия с публикации
  • минимальное значение — 12 190 руб.
  • максимальное значение — 763 млн руб.
  • медиана — 4,65 млн руб. и мода — 4,5 млн руб. расположены близко, а среднее арифметическое — 6,55 млн руб. отличается от них из-за наличия квартир с очень высокой ценой
  • половина всех значений расположено в промежутке 3,44—6,8 млн руб.
  • распределение значений унимодальное, с длинным "хвостом" справа
Цена за квадратный метр¶
In [497]:
descriptive_statistics(data['price_per_square_meter'],
                       'Цена за квадратный метр, руб.')
Out[497]:
Цена за квадратный метр, руб.
кол-во значений 23439
кол-во уникальных 14195
мин. 112
-1.5IQR 38749.25
25 % 76635.0
мода [100000]
медиана 95000.0
среднее ариф. 99365.74
75 % 114135.5
+1.5IQR 151250.75
макс. 1907500
размах 1907388
межквартильный размах 37500.5
In [498]:
plt.title('Диаграмма размаха' +
          '\nраспределения объявлений по цене одного квадратного метра')
data['price_per_square_meter'].plot.box(
    vert=False,
    xlabel='Цена квадратного метра, руб.',
    figsize=(10, 2))
plt.tick_params(left=False, labelleft=False)
plt.show()
In [499]:
plt.title('Диаграмма распределения объявлений' +
          '\nпо цене одного квадратного метра')
data['price_per_square_meter'].plot.hist(
    bins=[1000 * (n + 1) for n in range(200)],
    figsize=(10, 3))
plt.xlabel('Цена квадратного метра, руб.')
plt.ylabel('Количество объявлений')
plt.show()

Топ-10 значений цены за квадратный метр.

In [500]:
pd.DataFrame(data['price_per_square_meter'].value_counts()) \
    .reset_index() \
    .rename(columns={
                'price_per_square_meter': 'Цена квадратного метра, руб.',
                'count': 'Частота'}
    ).set_index('Цена квадратного метра, руб.').head(10).T
Out[500]:
Цена квадратного метра, руб. 100000 83333 75000 125000 66667 80000 90000 50000 116667 90909
Частота 261 69 59 52 52 51 47 47 37 37
  • для всех объявлений известна цена за квадратный метр
  • минимальное значение — 112 руб. за квадратный метр
  • максимальное значение — 1,9 млн. руб. за квадратный метр
  • медиана — 95 тыс. руб., мода — 100 тыс. руб., среднее арифметическое — 99 тыс. руб. за квадратный метр расположены близко
  • половина всех значений расположено в промежутке 77—114 тыс. руб. за квадратный метр
  • распределение значений унимодальное, симметричное, похоже на нормальное распределение

Дополнительные данные¶

Количество фотографий¶
In [501]:
descriptive_statistics(data['total_images'], 'Количество фотографий')
Out[501]:
Количество фотографий
кол-во значений 23439
кол-во уникальных 38
мин. 0
-1.5IQR -3.0
25 % 6.0
мода [10]
медиана 9.0
среднее ариф. 9.86
75 % 14.0
+1.5IQR 21.0
макс. 50
размах 50
межквартильный размах 8.0
In [502]:
plt.title('Диаграмма распределения объявлений\nпо количеству фотографий')
data['total_images'].plot.hist(bins=[n for n in range(51)])
plt.xlabel('Количество фотографий')
plt.ylabel('Количество объявлений')
plt.show()

Топ-5 количества фотографий.

In [503]:
pd.DataFrame(data['total_images'].value_counts()) \
    .reset_index() \
    .rename(columns={
                'total_images': 'Количество фотографий',
                'count': 'Частота'}
    ).set_index('Количество фотографий').head().T
Out[503]:
Количество фотографий 10 9 20 8 7
Частота 1780 1701 1679 1569 1506
  • для всех объявлений известно количество фотографий
  • минимальное значение — 0, что говорит об отсутствии фотографий в объявлении; частота этого значения — 1046 (около 4,5 %)
  • максимальное значение — 50
  • медиана — 9, мода — 10
  • наибольшее число объявлений сопровождается 6—10 или 20 фотографиями
  • большинство значений расположено в диапазоне 0—20
  • объявления с количеством фотографий больше 20 редкие
  • распределение значений в диапазоне 0—20 унимодальное, симметричное, с резко возрастающими значениями на краях диапазона

Корреляционный анализ данных¶

In [504]:
plt.title('Тепловая карта\nматрицы корреляции' +
          '\nзначений количественных признаков')
sns.heatmap(data[[
    'last_price', 'price_per_square_meter', 'total_area', 'living_area',
    'kitchen_area', 'ceiling_height', 'city_centers_nearest',
    'airports_nearest', 'parks_nearest', 'ponds_nearest', 'days_exposition'
    ]].corr())
plt.show()
  • Необходимо уделить внимание анализу связи между стоимостью объекта и общей площадью, жилой площадью, площадью кухни.
In [505]:
plt.title('Тепловая карта\nматрицы корреляции' +
          '\nзначений категориальных признаков' +
          '\n(и признаков, представленных как категориальные)')
sns.heatmap(data[[
    'last_price', 'price_per_square_meter', 'total_area', 'living_area',
    'kitchen_area', 'ceiling_height', 'city_centers_nearest',
    'airports_nearest', 'parks_nearest', 'ponds_nearest', 'days_exposition',
    'rooms', 'balcony', 'floor', 'floors_total', 'parks_around_3000',
    'ponds_around_3000', 'year', 'month', 'weekday', 'total_images'
    ]].corr(method='kendall'))
plt.show()
  • Необходимо уделить внимание анализу связи между стоимостью объекта и высотой потолков, количеством комнат, количеством парков и водоёмов.

Средняя цена квадратного метра¶

Топ-10 населённых пунктов с наибольшим числом объявлений (в соответствии с перечнем населённых пунктов, указанных в наборе данных).

In [506]:
pd.DataFrame([
    data['locality_name'].value_counts(),
    data.groupby('locality_name')['price_per_square_meter'].mean().round(0).astype('int')
    ]).T.head(10) \
    .reset_index().rename(
        columns={'locality_name': '',
                 'count': 'Количество объявлений',
                 'price_per_square_meter': 'Цена за квадратный метр, руб.'}) \
    .set_index('')
Out[506]:
Количество объявлений Цена за квадратный метр, руб.
Санкт-Петербург 15608 114670
Мурино 577 85809
Кудрово 465 95202
Шушары 437 78549
Всеволожск 390 68473
Пушкин 370 102969
Колпино 337 75481
Парголово 325 90069
Гатчина 303 68625
Выборг 233 58345

Топ-10 населённых пунктов с наибольшим числом объявлений (в соответствии с административно-территориальным делением).

In [507]:
pd.DataFrame([
    data.loc[data['is_spb'] == False, 'locality_name'].value_counts(),
    data.loc[data['is_spb'] == False].groupby('locality_name') \
    ['price_per_square_meter'].mean().round(0).astype('int')]).rename(
        index={'count': 'Количество объявлений',
               'price_per_square_meter': 'Цена квадратного метра, руб.'}
        ).join(pd.DataFrame({
            'Санкт-Петербург': [
                data['is_spb'].sum(),
                data.loc[data['is_spb'], 'price_per_square_meter'].mean().round(0).astype('int')
                ]
            }).rename(index={0: 'Количество объявлений',
                             1: 'Цена квадратного метра, руб.'})
            ).T.sort_values(by='Количество объявлений',
                            ascending=False).head(10)
Out[507]:
Количество объявлений Цена квадратного метра, руб.
Санкт-Петербург 18080 110640
Мурино 577 85809
Кудрово 465 95202
Всеволожск 390 68473
Гатчина 303 68625
Выборг 233 58345
Новое Девяткино 141 75860
Сертолово 141 69319
Кириши 124 38642
Бугры 112 80512

Согласно перечню населённых пунктов набора данных:

  • самое большое количество объявлений поступает о продаже объектов недвижимости, расположенных в Санкт-Петербурге, Мурино и Кудрово
  • меньше всего в топ-10 поступает объявлений о продаже объектов недвижимости, расположенных в Парголово, Гатчине и Выборге
  • стоимость одного квадратного метра варьируется от 58 до 115 тыс. руб.
  • однако среди топ-10 населённых пунктов с наибольшим числом объявлений четыре из них входят в административную границу города Санкт-Петербурга

Согласно административно-территориальному делению:

  • самое большое количество объявлений поступает о продаже объектов недвижимости, расположенных в городах Санкт-Петербурге, Кудрово и Мурино; два последних, фактически, являются городами-спутниками Санкт-Петербурга
  • стоимость одного квадратного метра в этих городах варьируется в пределах от 86 тыс. руб. в Мурино до 111 тыс. руб. в Санкт-Петербурге
  • меньше всего в топ-10 поступает объявлений о продаже объектов недвижимости, расположенных в Сертолово, Киришах и Буграх
  • стоимость одного квадратного метра в этих населённых пунктах варьируется в пределах от 39 до 81 тыс. руб.

Средняя стоимость квартир в Санкт-Петербурге¶

In [508]:
data['city_centers_km_int'] = (data['city_centers_nearest'] / 1000).round(0)
In [509]:
plt.title('График зависимости\nсредней стоимости объекта недвижимости' +
          '\nот расстояния до центра Санкт-Петербурга')
data[data['is_spb']].groupby('city_centers_km_int')['last_price'].mean().plot(
    figsize=(6, 4))
plt.xlabel('Расстояние до центра, км')
plt.ylabel('Средняя стоимость объекта, руб.')
plt.show()

Топ-15 самых дорогих километров от центра.

In [510]:
pd.DataFrame(data[data['is_spb']].groupby('city_centers_km_int') \
    ['last_price'].mean().sort_values(ascending=False)).head(15) \
    .reset_index().rename(
        columns={'city_centers_km_int': 'Расстояние до центра, км',
                 'last_price': 'Средняя стоимость объекта, руб.'})
Out[510]:
Расстояние до центра, км Средняя стоимость объекта, руб.
0 1.0 2.130401e+07
1 0.0 1.926459e+07
2 2.0 1.791487e+07
3 6.0 1.538862e+07
4 7.0 1.483441e+07
5 5.0 1.450482e+07
6 4.0 1.329379e+07
7 43.0 1.153148e+07
8 3.0 1.111668e+07
9 8.0 9.928107e+06
10 55.0 9.000000e+06
11 9.0 6.927587e+06
12 10.0 6.510731e+06
13 54.0 6.273150e+06
14 11.0 6.258976e+06
  • самые дорогие объекты недвижимости расположены в пределах 7 км от центра города Санкт-Петербурга
  • средняя стоимость объектов недвижимости в радиусе 7 км от центра города составляет от 11 до 21 млн руб.
  • в пределах от 10 до 65 км от центра города средняя стоимость объектов недвижимости снижается и составляет около 5 млн руб.
  • на графике наблюдаются два резких максимума на расстоянии 43 и 55 км от центра города, средняя стоимость объектов недвижимости там составляет 12 и 9 млн руб., соответственно

Стоимость объекта — общая площадь¶

In [511]:
data.plot.scatter(
    x='total_area',
    y='last_price',
    xlabel='Общая площадь, м$^2$',
    ylabel='Цена объекта, руб.',
    title='Диаграмма рассеяния\nзначений цены объекта недвижимости' +
          '\nпо значениям общей площади',
    alpha=0.2,
    figsize=(10, 3))
plt.show()

Коэффициент корреляции.

In [512]:
data['last_price'].corr(data['total_area']).round(2)
Out[512]:
0.65
In [513]:
plt.title('График зависимости\nсредней стоимости объекта от общей площади')
data.groupby('total_area')['last_price'].mean().plot(figsize=(10, 3))
plt.xlabel('Общая площадь, м$^2$')
plt.ylabel('Средняя стоимость\nобъекта, руб.')
plt.show()
In [514]:
plt.title('График зависимости' +
          '\nсредней стоимости объекта от общей площади для значений,' +
          '\nпопадающих в размах "усов" на диаграмме размаха')
data[(data['last_price'] <= data['last_price'].median() +
      1.5 * (data['last_price'].quantile(q=.75) -
             data['last_price'].quantile(q=.25))) &
     (data['total_area'] <= data['total_area'].median() +
      1.5 * (data['total_area'].quantile(q=.75) -
             data['total_area'].quantile(q=.25)))
    ].groupby('total_area')['last_price'].mean().plot(figsize=(10, 3))
plt.xlabel('Общая площадь, м$^2$')
plt.ylabel('Средняя стоимость\nобъекта, руб.')
plt.show()
  • по мере увеличения общей площади объекта увеличивается стоимость объекта
  • коэффициент корреляции Пирсона — 0,65, что свидетельствует о возможном наличии положительной линейной связи, значительной степени выраженности
  • зависимость среднего значения стоимости объекта от общей площади носит возрастающий характер, тенденция особенно заметна (несмотря на значительный шум) для значений общей площади, попадающих в размах "усов" на диаграмме размаха (т. е. для большинства объектов недвижимости)

Стоимость объекта — жилая площадь¶

In [515]:
data.plot.scatter(
    x='living_area',
    y='last_price',
    xlabel='Жилая площадь, м$^2$',
    ylabel='Цена объекта, руб.',
    title='Диаграмма рассеяния\nзначений цены объекта недвижимости' +
          '\nпо значениям жилой площади',
    alpha=0.2,
    figsize=(10, 3))
plt.show()

Коэффициент корреляции.

In [516]:
data['last_price'].corr(data['living_area']).round(2)
Out[516]:
0.56
In [517]:
plt.title('График зависимости' +
          '\nсредней стоимости объекта недвижимости от жилой площади')
data.groupby('living_area')['last_price'].mean().plot(figsize=(10, 3))
plt.xlabel('Жилая площадь, м$^2$')
plt.ylabel('Средняя стоимость\nобъекта, руб.')
plt.show()
In [518]:
plt.title('График зависимости\nсредней стоимости объекта от жилой площади' +
          '\nдля значений, попадающих в размах "усов" на диаграмме размаха')
data.loc[(data['last_price'] <= data['last_price'].median() +
          1.5 * (data['last_price'].quantile(q=.75) -
                 data['last_price'].quantile(q=.25))) &
         (data['living_area'] <= data['living_area'].median() +
          1.5 * (data['living_area'].quantile(q=.75) -
                 data['living_area'].quantile(q=.25)))
        ].groupby('living_area')['last_price'].mean().plot(figsize=(10, 3))
plt.xlabel('Жилая площадь, м$^2$')
plt.ylabel('Средняя стоимость\nобъекта, руб.')
plt.show()
  • по мере увеличения жилой площади объекта увеличивается стоимость объекта
  • коэффициент корреляции Пирсона — 0,56, что свидетельствует о возможном наличии положительной линейной связи, значительной степени выраженности
  • зависимость среднего значения стоимости объекта от жилой площади носит возрастающий характер, тенденция особенно заметна (несмотря на значительный шум) для значений жилой площади, попадающих в размах "усов" на диаграмме размаха (т. е. для большинства объектов недвижимости)

Стоимость объекта — площадь кухни¶

In [519]:
data.plot.scatter(
    x='kitchen_area',
    y='last_price',
    xlabel='Площадь кухни, м$^2$',
    ylabel='Цена объекта, руб.',
    title='Диаграмма рассеяния\nзначений цены объекта недвижимости' +
          '\nпо значениям площади кухни',
    alpha=0.2,
    figsize=(10, 3))
plt.show()

Коэффициент корреляции.

In [520]:
data['last_price'].corr(data['kitchen_area']).round(2)
Out[520]:
0.46
In [521]:
plt.title('График зависимости' +
          '\nсредней стоимости объекта недвижимости от площади кухни')
data.groupby('kitchen_area')['last_price'].mean().plot(figsize=(10, 3))
plt.xlabel('Площадь кухни, м$^2$')
plt.ylabel('Средняя стоимость\nобъекта, руб.')
plt.show()
In [522]:
plt.title('График зависимости\nсредней стоимости объекта от площади кухни' +
          '\nдля значений, попадающих в размах "усов" на диаграмме размаха')
data.loc[(data['last_price'] <= data['last_price'].median() +
          1.5 * (data['last_price'].quantile(q=.75) -
                 data['last_price'].quantile(q=.25))) &
         (data['kitchen_area'] <= data['kitchen_area'].median() +
          1.5 * (data['kitchen_area'].quantile(q=.75) -
                 data['kitchen_area'].quantile(q=.25)))
        ].groupby('kitchen_area')['last_price'].mean().plot(figsize=(10, 3))
plt.xlabel('Площадь кухни, м$^2$')
plt.ylabel('Средняя стоимость\nобъекта, руб.')
plt.show()
  • по мере увеличения площади кухни объекта недвижимости увеличивается его стоимость
  • коэффициент корреляции Пирсона — 0,46, что свидетельствует о возможном наличии положительной линейной связи, средней степени выраженности
  • зависимость среднего значения стоимости объекта от площади кухни носит возрастающий характер, тенденция особенно заметна (несмотря на значительный шум) для значений жилой площади, попадающих в размах "усов" на диаграмме размаха (т. е. для большинства объектов недвижимости)

Стоимость объекта — количество комнат¶

In [523]:
data.plot.scatter(
    x='rooms',
    y='last_price',
    xlabel='Количество комнат',
    ylabel='Цена объекта, руб.',
    title='Диаграмма рассеяния\nзначений цены объекта недвижимости' +
          '\nпо значениям количества комнат',
    xticks=[n + 1 for n in range(19)],
    alpha=0.2,
    figsize=(10, 3))
plt.show()

Коэффициент корреляции.

In [524]:
data['last_price'].corr(data['rooms'], method='kendall').round(2)
Out[524]:
0.42
In [525]:
plt.title('График зависимости' +
          '\nсредней стоимости объекта от количества жилых комнат')
data.groupby('rooms')['last_price'].mean().plot(
    xticks=[n + 1 for n in range(19)],
    figsize=(10, 3))
plt.xlabel('Количество комнат')
plt.ylabel('Средняя стоимость\nобъекта, руб.')
plt.show()
In [526]:
plt.title('График зависимости' +
          '\nсредней стоимости объекта от количества жилых комнат' +
          '\nдля значений, попадающих в размах "усов" на диаграмме размаха')
data[(data['last_price'] <= data['last_price'].median() +
      1.5 * (data['last_price'].quantile(q=.75) -
             data['last_price'].quantile(q=.25))) &
     (data['rooms'] <= data['rooms'].median() +
      1.5 * (data['rooms'].quantile(q=.75) -
             data['rooms'].quantile(q=.25)))
    ].groupby('rooms')['last_price'].mean().plot(
        xticks=[n + 1 for n in range(5)],
        figsize=(10, 3))
plt.xlabel('Количество комнат')
plt.ylabel('Средняя стоимость\nобъекта, руб.')
plt.show()
  • коэффициент корреляции Кендалла — 0,42, что свидетельствует о возможном наличии положительной линейной связи, средней степени выраженности
  • для объектов недвижимости с 1—5 жилыми комнатами (объекты, попавшие в размах "усов" на диаграмме размаха — т. е. большинство объектов недвижимости) наблюдается уширение диапазона значений цены объекта недвижимости
  • для объектов недвижимости с 1—5 жилыми комнатами наблюдается зависимость среднего значения стоимости объекта недвижимости от количества комнат; зависимость носит возрастающий, практически линейный характер

Стоимость объекта — тип этажа¶

In [527]:
data.plot.scatter(
    x='floor_type',
    y='last_price',
    xlabel='Тип этажа',
    ylabel='Цена объекта, руб.',
    title='Диаграмма рассеяния\nзначений цены объекта недвижимости' +
          '\nпо значениям типа этажа',
    alpha=0.2,
    figsize=(5, 3))
plt.show()
In [528]:
plt.title('График зависимости\nсредней стоимости объекта недвижимости' +
          '\nот типа этажа')
data.groupby('floor_type')['last_price'].mean().plot(figsize=(5, 3))
plt.xlabel('Тип этажа')
plt.ylabel('Средняя стоимость\nобъекта, руб.')
plt.show()
In [529]:
plt.title('График зависимости\nсредней стоимости объекта от типа этажа' +
          '\nдля значений, попадающих в размах "усов" на диаграмме размаха')
data.loc[data['last_price'] <= data['last_price'].median() +
         1.5 * (data['last_price'].quantile(q=.75) -
                data['last_price'].quantile(q=.25))
         ].groupby('floor_type')['last_price'].mean().plot(figsize=(8, 3))
plt.xlabel('Тип этажа')
plt.ylabel('Средняя стоимость\nобъекта, руб.')
plt.show()
  • на диаграмме рассеяния "стоимость объекта — тип этажа" наблюдается уширение диапазона цен за объект при переходе от первого этажа к последнему
  • кроме того, наблюдается зависимость среднего значения стоимости объекта от типа этажа; зависимость носит возрастающий, нелинейный характер: самый дешёвый — первый этаж, самый дорогой — последний. На такое распределение оказывают значительное влияние самые дорогие объекты недвижимости, расположенные в пентхаусе
  • для большинства же объектов недвижимости (значения попадают в размах "усов" на диаграмме размаха) наблюдается иная картина: самыми дешёвыми являются первый и последний этажи; остальные этажи в среднем на 15—20 % дороже

Стоимость объекта — день недели публикации¶

In [530]:
data.plot.scatter(
    x='weekday',
    y='last_price',
    xlabel='День недели публикации',
    ylabel='Цена объекта, руб.',
    title='Диаграмма рассеяния\nзначений цены объекта недвижимости' +
          '\nпо значениям дней недели публикации объявления',
    alpha=0.2,
    figsize=(6, 3))
plt.xticks(np.arange(7), ['пн', 'вт', 'ср', 'чт', 'пт', 'сб', 'вс'])
plt.show()
In [531]:
plt.title('График зависимости' +
          '\nсредней стоимости объекта недвижимости от дня недели публикации')
data.groupby('weekday')['last_price'].mean().plot(figsize=(10, 3))
plt.xlabel('День недели публикации')
plt.ylabel('Средняя стоимость\nобъекта, руб.')
plt.xticks(np.arange(7), ['пн', 'вт', 'ср', 'чт', 'пт', 'сб', 'вс'])
plt.show()
In [532]:
plt.title('График зависимости' +
          '\nсредней стоимости объекта от дня недели публикации' +
          '\nдля значений, попадающих в размах "усов" на диаграмме размаха')
data.loc[data['last_price'] <= data['last_price'].median() +
         1.5 * (data['last_price'].quantile(q=.75) -
                data['last_price'].quantile(q=.25))
         ].groupby('weekday')['last_price'].mean().plot(figsize=(10, 3))
plt.xlabel('День недели публикации')
plt.ylabel('Средняя стоимость\nобъекта, руб.')
plt.xticks(np.arange(7), ['пн', 'вт', 'ср', 'чт', 'пт', 'сб', 'вс'])
plt.show()
  • на диаграмме рассеяния "стоимость объекта — день недели публикации" диапазон цен в каждый день недели практически не изменяется
  • если исключить из анализа дорогие объекты недвижимости (не попадающие в размах "усов" на диаграмме размаха), то можно заметить, что объявления с самыми дорогими объектами недвижимости публиковали с понедельника по среду, а с самыми дешёвыми — в воскресенье

Стоимость объекта — месяц публикации¶

In [533]:
data.plot.scatter(
    x='month',
    y='last_price',
    xlabel='Месяц публикации',
    ylabel='Цена объекта, руб.',
    title='Диаграмма рассеяния\nзначений цены объекта недвижимости' +
          '\nпо значениям месяца публикации объявления',
    xticks=[n + 1 for n in range(12)],
    alpha=0.2,
    figsize=(6, 3))
plt.show()
In [534]:
plt.title('График зависимости' +
          '\nсредней стоимости объекта недвижимости от месяца публикации')
data.groupby('month')['last_price'].mean().plot(
    xticks=[n + 1 for n in range(12)],
    figsize=(10, 3))
plt.xlabel('Месяц публикации')
plt.ylabel('Средняя стоимость\nобъекта, руб.')
plt.show()
In [535]:
plt.title('График зависимости\nсредней стоимости объекта от месяца публикации' +
          '\nдля значений, попадающих в размах "усов" на диаграмме размаха,' +
          '\nза период 2015—2018 гг.')
data[(data['last_price'] <= data['last_price'].median() +
      1.5 * (data['last_price'].quantile(q=.75) -
             data['last_price'].quantile(q=.25))) &
     (data['year'] > 2014) & (data['year'] < 2019)
     ].groupby('month')['last_price'].mean().plot(
    xticks=[n + 1 for n in range(12)],
    figsize=(10, 3))
plt.xlabel('Месяц публикации')
plt.ylabel('Средняя стоимость\nобъекта, руб.')
plt.show()
  • на диаграмме рассеяния "стоимость объекта — месяц публикации" диапазон цен в каждый месяц изменяется незначительно
  • если исключить из анализа дорогие объекты недвижимости (не попадающие в размах "усов" на диаграмме размаха) и рассматривать объявления за полные 4 года (с 2015 по 2018 гг.), то можно заметить, что объявления с самыми дорогими объектами недвижимости публиковали в последние три месяца года (октябрь, ноябрь, декабрь), а с самыми дешёвыми — в первые три месяца года (январь, февраль и март) и в июне
  • в общем, во вторую половину года публикуются объявления с более дорогими квартирами, чем в первую половину года

Стоимость объекта — год публикации¶

In [536]:
data.plot.scatter(
    x='year',
    y='last_price',
    xlabel='Год публикации',
    ylabel='Цена объекта, руб.',
    title='Диаграмма рассеяния\nзначений цены объекта недвижимости' +
          '\nпо значениям года публикации объявлений',
    alpha=0.2,
    figsize=(6, 3))
plt.show()
In [537]:
plt.title('График зависимости' +
          '\nсредней стоимости объекта недвижимости от года публикации')
data.groupby('year')['last_price'].mean().plot(figsize=(10, 3))
plt.xlabel('Год публикации')
plt.ylabel('Средняя стоимость\nобъекта, руб.')
plt.show()
In [538]:
plt.title('График зависимости' +
          '\nсредней стоимости объекта недвижимости от года публикации' +
          '\nдля значений, попадающих в размах "усов" на диаграмме размаха')
data.loc[data['last_price'] <= data['last_price'].median() +
         1.5 * (data['last_price'].quantile(q=.75) -
                data['last_price'].quantile(q=.25))
         ].groupby('year')['last_price'].mean().plot(figsize=(10, 3))
plt.xlabel('Месяц публикации')
plt.ylabel('Средняя стоимость\nобъекта, руб.')
plt.show()
  • на диаграмме рассеяния "стоимость объекта — год публикации" разброс цен увеличивается к 2017 году
  • если исключить из анализа дорогие объекты недвижимости (не попадающие в размах "усов" на диаграмме размаха), то можно заметить снижение средней стоимости объекта в период с 2014 по 2016 гг. — средняя стоимость снизилась почти в два раза
  • на протяжении 2016—2018 гг. средняя стоимость сохранялась на низком уровне
  • уже за первые 4 месяца 2019 года средняя стоимость увеличилась по сравнению с 2018 годом

Общий вывод¶

*Характеристики объявлений*

Данные собраны за период 4,5 года — с 27 ноября 2014 г. по 3 мая 2019 г. За это время было опубликовано около 23,5 тыс. объявлений. Причём половину объявлений опубликовали за первые 3 года, а вторую половину — за оставшиеся 1,5 года. Это свидетельствует об увеличении объёма публикаций в единицу времени.

Всего за рассматриваемый период времени в наборе данных находятся объявления, опубликованные в 6 различных календарных годах. В рассматриваемом периоде содержатся полные 4 года — 2015–2018 гг., первая треть 2019 года и последний месяц 2014 года. В 2014 году, когда до конца года оставалось немногим более месяца, было опубликовано всего 134 объявления. В 2015 году было опубликовано 1183 объявления — минимальное число публикуемых объявлений в год. В 2016 году наблюдался рост числа опубликованных почти в 2,5 раза по сравнению с предыдущим годом — до 2762 объявлений. В 2017 году рост продолжился. По сравнению с 2016 годом количество объявлений, опубликованных за год, увеличилось в 3 раза и составило 8112 объявлений. В 2018 году количество опубликованных объявлений осталось почти на таком же уровне, как и годом ранее, — 8403 объявления (рост менее 4 %). За рассматриваемый период это максимальное число объявлений, опубликованных за один год. В 2019 году только за первые четыре месяца было опубликовано примерно такое же количество объявлений, как за весь 2016 год.

В среднем за 4 года — с 2015 по 2018 гг. — количество объявлений, публикуемых в течение года, изменялось неравномерно. Так, меньше всего объявлений публиковалось в январе, больше всего — в ноябре. В феврале количество публикуемых объявлений растёт почти в 2 раза по сравнению с январём. С февраля по май наблюдается снижение, а с мая по июнь наблюдается рост количества публикуемых объявлений. С июня по август количество опубликованных объявлений остаётся на приблизительно одинаковом уровне. С августа по ноябрь наблюдается рост, а с ноября по январь происходит снижение количества публикуемых объявлений. Однако для каждого года наблюдается своя картина распределения количества публикаций объявлений по месяцам.

По дням недели распределение количества публикуемых объявлений тоже неравномерное. Количество публикуемых объявлений в будние дни отличается от количества публикуемых объявлений в выходные: в субботу или воскресенье количество опубликованных объявлений в среднем в два раза меньше, чем в будний день.

Число публикаций объявлений растёт со средней скоростью 10 объявлений в день. Практически всегда число публикаций в день не превышает 50, но не менее 1. Максимальное число объявлений, опубликованных в течение одного дня, составило 359.

На момент получения данных опубликованными остаются 3150 объявлений. 20 289 объявлений к этому моменту были сняты с публикации. Большинство объявлений остаются опубликованными не более одного года. В среднем одно объявление остаётся опубликованным 96 дней (3 месяца). Наиболее частые случаи, когда объявления остаются опубликованными в течение 7, 14, 30, 45, 90 дней.

Почти 20 % всех объявлений снимают с публикации в течение первых 30 дней. Ещё 30 % объявлений остаются опубликованными в течение 30-90 дней. До полугода остаются опубликованными ещё 20 %, до года — ещё 15 %. Оставшиеся 15 % объявлений находились на сайте более одного года. Максимальный период, в течение которого объявление находилось на сайте, составляет 1510 дней (почти 4,5 года).

Из объявлений, продолжающих оставаться опубликованными на сайте, половина их находится на сайте около 3 месяцев. Ещё 30 % объявлений остаются опубликованными в течение года, а оставшиеся 20 % — более года (но не более 2 лет).

Снимать объявления с публикации начали 16 июня 2016 года, до этого дня объявления только публиковались. Из всех снятых с публикации объявлений в период с июня 2016 года по апрель 2018 года (в течение почти 2 лет) была снята половина объявлений, вторая половина объявлений была снята в период с апреля 2018 года по май 2019 года (в течение одного года). Это говорит об увеличении скорости не только публикации, но и снятия объявлений с публикации.

*Характеристики зданий и их местоположений*

Большинство объектов недвижимости (77 %), предлагаемых в объявлениях, расположены в границах города Санкт-Петербурга, что в 3 раза больше, чем количество объектов в Ленинградской области. Число объектов, расположенных в городских населённых пунктах (83 %), в 7 раз больше числа объектов, расположенных в сельских пунктах (13 %).

На сайте предлагают объекты недвижимости, расположенные в 310 населённых пунктах: 286 различных населённых пунктов находится в Ленинградской области. 23 населённых пункта находятся в черте города Санкт-Петербурга. Из всех населённых пунктов на города приходятся только 10 %, а из населённых пунктов Ленинградской области треть являются деревнями и столько же — посёлками. Таким образом, большое количество различных сельских населённых пунктов связано с малым количество выставляемой там на продажу недвижимости. В то же время, в небольшом количестве городских населённых пунктов выставляется на продажу значительное количество объектов недвижимости.

Объекты недвижимости располагаются не ближе 200 м к центру Санкт-Петербурга, но не далее 66 км от центра. В среднем объекты недвижимости располагаются на расстоянии 14 км от центра Санкт-Петербурга. Большинство всех объектов недвижимости расположены на расстоянии 2,6–23,6 км от центра Санкт-Петербурга, это определяется, главным образом, объектами недвижимости, расположенными в черте города Санкт-Петербурга.

Большинство объектов недвижимости расположены от аэропорта Пулково на расстоянии не более 55 км. Самый близко расположенный объект находится на расстоянии 6,4 км от аэропорта. Расстояние до аэропорта от самых далёких объектов недвижимости составляет 85 км. В среднем до аэропорта от объекта недвижимости 29 км.

Не для всех объектов недвижимости известны сведения о расположении в радиусе 3 км парков и водоёмов. Только 77 % объявлений содержат сведения о парках и водоёмах. Все эти объекты расположены в черте города Санкт-Петербурга.

Отношение количества объектов недвижимости, имеющих доступ хотя бы к одному к парку в радиусе 3 км, к количеству объектов недвижимости, не имеющих такового, составляет 5 : 4. Из тех объектов, которые имеют в радиусе 3 км по крайней мере один парк, 70 % имеют только 1 парк, 22 % — 2 парка, 8 % — 3 парка. В среднем расстояние до ближайшего парка составляет 450 м.

Отношение количества объектов недвижимости, имеющих доступ хотя бы к одному водоёму в радиусе 3 км, к количеству объектов недвижимости, не имеющих такового, составляет 1 : 1. Из тех объектов, которые имеют в радиусе 3 км по крайней мере один водоём, 63 % имеют только 1 водоём, 21 % — 2 водоёма, 16 % — 3 водоёма. В среднем расстояние до ближайшего водоёма составляет 500 м.

Все объекты недвижимости расположены в зданиях разной этажности: от 1-этажных до 29-этажных и одно 35-этажное здание — самое высокое в Санкт-Петербурге и Ленинградской области. Чаще всего объявления содержат информацию об объектах недвижимости, расположенных в 5-этажных зданиях (почти четверть всех объявлений — 24,5 %). Кроме того, наибольшее количество объектов недвижимости расположено в зданиях в 9, 12, 16, 25 этажей — среди которых много типовых зданий; также большое количество объявлений содержат сведения об объектах недвижимости, расположенных в 4- и 10-этажных зданиях.

*Характеристики объектов недвижимости*

Четверть всех объектов недвижимости расположено либо на первом, либо на последнем этажах: причём их количество распределено почти поровну (12 % и 14 %, соответственно). Наибольшее число объектов недвижимости расположено с 1 по 5 этажи, включительно. Среди них чаще всего попадаются объекты, расположенных на 2 этаже. Почти в два раза реже встречаются объявления об объектах недвижимости, расположенных на этажах с 6 по 9, включительно. Ещё в два раза реже встречаются объявления об объектах недвижимости, расположенных на этажах с 10 по 12. Ещё более редкие — объекты недвижимости, расположенные на этажах с 12 по 17, включительно, ещё реже встречаются объекты недвижимости, расположенные на этажах с 18 по 25. Практически не встречаются объекты недвижимости, расположенные выше 25 этажа.

Большинство квартир — 1-, 2- или 3-комнатные: на них приходится почти 93 % всех объявлений. Лишь 5 % всех объявлений содержат сведения о 4-комнатных квартирах, а около 2 % объявлений — о квартирах с 5 и более жилыми комнатами. Больше всего предлагают 1- и 2-комнатные квартиры — количество таких объявлений составляет 68 %, и распределены они поровну между 1- и 2-комнатными квартирами. Четверть всех объявлений (25 %) содержит сведения о 3-комнатных квартирах. Большинство квартир не имеют балконов — 64,5 %, только 35,5 % объявлений имеют балконы: в основном, один или два. Менее 2,% % квартир имеют от 3 до 5 балконов.

Общая площадь большинства квартир не превышает 97 м$^2$. В среднем площадь квартир составляет 50 м$^2$. Попадаются объекты недвижимости как с очень маленькими площадами (минимальная общая площадь — 13 м$^2$), так и с очень большими (максимальная общая площадь — 900 м$^2$). При этом жилая площадь не превышает 66 м$^2$. Может изменяться от 6 до 410 м$^2$. Но в среднем составляет 30 м$^2$. Площадь кухни изменяется от 2 до 112 м$^2$. Но большинство объектов недвижимости имеют кухню площадью не более 17 м$^2$. В среднем на кухню приходится 9 м$^2$. Высота потолков в квартирах изменяется от 2 до 6 м. В большинстве квартир высота потолков изменяется от 2,2 до 3 м. Среднее значение высоты потолков оставляет 2,65 м.

В наборе данных редко встречаются квартиры-студии. Только 1 % всех квартир имеют свободную планировку и могу считаться квартирами-студиями. Среди объявлений почти не найти апартаментов. Преимущественно все объекты недвижимости относятся к жилым помещениям. Только 0,2 % всех объектов недвижимости являются апартаментами.

Не все объявления сопровождаются фотографиями объекта недвижимости: 4,5 % квартир не имеют своих изображений. В среднем к объявлению прикладывают 9–10 фотографий. Большинство объектов недвижимости сопровождаются не более 20 фотографиями.

*Финансовые характеристики*

Стоимость большинства объектов недвижимости не превышает 9,69 млн руб. Есть квартиры как с минимальной стоимостью в 12 тыс. руб., так и с максимальной стоимостью в 763 млн руб., что скорее является исключение, нежели правилом. Половина всех предлагаемых квартир стоит 3,44–6,8 млн руб., а в среднем — 4,65 млн руб.

Цена за квадратный метр в среднем составляет 95 тыс. руб. А у половины всех объектов недвижимости цена за квадратный метр изменяется в диапазоне 77–114 тыс. руб. Минимальная цена квадратного метра составляет 112 руб., максимальная — 1,9 млн руб. Самая высокая цена за квадратный метр у объектов недвижимости, расположенных в Санкт-Петербурге, — 110 тыс. руб. Затем следуют объекты недвижимости, расположенные в Кудрово и Мурино — городах-спутниках Санкт-Петербурга. Стоимость квадратного метра там составляет 95 тыс. и 86 тыс. руб. В этих трёх городах предлагается больше всего объектов недвижимости для продажи. Помимо этих городов в топ-10 населённых пунктов по количеству объектов недвижимости для продажи входят (в порядке уменьшения предложения) Всеволожск, Гатчина, Выборг, Новое Девяткино, Сертолово, Кириши и Бугры. Стоимость квадратного метра в этих населённых пунктах изменяется от 39 тыс. до 81 тыс. руб.

В Санкт-Петербурге к продаже предлагалось более 18 тыс. объектов недвижимости. Все они находятся на разном удалении от центра города. Самые дорогие объекты недвижимости расположены в пределах 7 км от центра Санкт-Петербурга: средняя стоимость объектов недвижимости в радиусе 7 км от центра города составляет от 11 до 21 млн руб. В пределах от 10 до 65 км от центра города средняя стоимость объектов недвижимости снижается и составляет около 5 млн руб.

Наибольшее влияние на стоимость объектов недвижимости оказывает размер общей площади. Ожидается прямая положительная зависимость стоимости квартиры от значения общей площади. Значительное влияние на стоимость объектов недвижимости оказывают размер жилой площади, площади кухни и количество жилых комнат. Ожидается также прямая положительная зависимость стоимости квартиры от этих параметров.

Объекты недвижимости, расположенные на первых и последних этажах, как правило, стоят дешевле. Остальные этажи в среднем на 15—20 % дороже. Исключением являются квартиры, расположенные в пентхаусе: у них большая общая площадь, высокие потолки и значительно более высокая цена.

Объявления с самыми дорогими объектами недвижимости публиковали с понедельника по среду, а с самыми дешёвыми — в субботу и воскресенье. Объявления с самыми дорогими объектами недвижимости публиковали в последние три месяца года (октябрь, ноябрь, декабрь), а с самыми дешёвыми — в первые три месяца года (январь, февраль и март) и в июне. А в общем, во вторую половину года публикуются объявления с более дорогими квартирами, чем в первую половину года.

В период с 2014 по 2016 гг. средняя стоимость квартир снизилась почти в два раза. На протяжении 2016–2018 гг. средняя стоимость сохранялась на низком уровне. А уже за первые четыре месяца 2019 года средняя стоимость квартир увеличилась по сравнению с 2018 годом.